瀏覽代碼

Merge pull request #793 from bruvzg/v4_v4i_proj

Rémi Verschelde 3 年之前
父節點
當前提交
3cc1409210

+ 9 - 0
binding_generator.py

@@ -416,6 +416,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
         result.append("\tChar16String utf16() const;")
         result.append("\tChar32String utf32() const;")
         result.append("\tCharWideString wide_string() const;")
+        result.append("\tstatic String num_real(double p_num, bool p_trailing = true);")
 
     if "members" in builtin_api:
         for member in builtin_api["members"]:
@@ -506,6 +507,11 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
         result.append("String operator+(const char16_t *p_chr, const String &p_str);")
         result.append("String operator+(const char32_t *p_chr, const String &p_str);")
 
+        result.append("String itos(int64_t p_val);")
+        result.append("String uitos(uint64_t p_val);")
+        result.append("String rtos(double p_val);")
+        result.append("String rtoss(double p_val);")
+
     result.append("")
     result.append("} // namespace godot")
 
@@ -1685,6 +1691,9 @@ def is_included_type(type_name):
         "Vector2i",
         "Vector3",
         "Vector3i",
+        "Vector4",
+        "Vector4i",
+        "Projection",
     ]
 
 

文件差異過大導致無法顯示
+ 781 - 513
godot-headers/extension_api.json


+ 4 - 1
godot-headers/godot/gdnative_interface.h

@@ -67,11 +67,14 @@ typedef enum {
 	GDNATIVE_VARIANT_TYPE_VECTOR3,
 	GDNATIVE_VARIANT_TYPE_VECTOR3I,
 	GDNATIVE_VARIANT_TYPE_TRANSFORM2D,
+	GDNATIVE_VARIANT_TYPE_VECTOR4,
+	GDNATIVE_VARIANT_TYPE_VECTOR4I,
 	GDNATIVE_VARIANT_TYPE_PLANE,
 	GDNATIVE_VARIANT_TYPE_QUATERNION,
 	GDNATIVE_VARIANT_TYPE_AABB,
 	GDNATIVE_VARIANT_TYPE_BASIS,
 	GDNATIVE_VARIANT_TYPE_TRANSFORM3D,
+	GDNATIVE_VARIANT_TYPE_PROJECTION,
 
 	/* misc types */
 	GDNATIVE_VARIANT_TYPE_COLOR,
@@ -537,7 +540,7 @@ typedef struct {
 
 	void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
 	void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
-	void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, bool p_is_bitfield);
+	void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
 	void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
 	void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
 	void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);

+ 15 - 0
include/godot_cpp/core/error_macros.hpp

@@ -576,6 +576,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
 
 } // namespace godot
 
+/**
+ * This should be a 'free' assert for program flow and should not be needed in any releases,
+ *  only used in dev builds.
+ */
+#ifdef DEBUG_ENABLED
+#define DEV_ASSERT(m_cond)                                                                                              \
+	if (unlikely(!(m_cond))) {                                                                                          \
+		_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed  \"" _STR(m_cond) "\" is false."); \
+		GENERATE_TRAP();                                                                                                \
+	} else                                                                                                              \
+		((void)0)
+#else
+#define DEV_ASSERT(m_cond)
+#endif
+
 /**
  * Gives an error message when a method bind is invalid (likely the hash changed).
  * Avoids crashing the application in this case. It's not free, so it's debug only.

+ 15 - 0
include/godot_cpp/core/math.hpp

@@ -278,6 +278,21 @@ inline float lerp_angle(float p_from, float p_to, float p_weight) {
 	return p_from + distance * p_weight;
 }
 
+inline double cubic_interpolate(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
+	return 0.5 *
+		   ((p_from * 2.0) +
+				   (-p_pre + p_to) * p_weight +
+				   (2.0 * p_pre - 5.0 * p_from + 4.0 * p_to - p_post) * (p_weight * p_weight) +
+				   (-p_pre + 3.0 * p_from - 3.0 * p_to + p_post) * (p_weight * p_weight * p_weight));
+}
+inline float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
+	return 0.5f *
+		   ((p_from * 2.0f) +
+				   (-p_pre + p_to) * p_weight +
+				   (2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) +
+				   (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
+}
+
 template <typename T>
 inline T clamp(T x, T minv, T maxv) {
 	if (x < minv) {

+ 3 - 0
include/godot_cpp/core/method_ptrcall.hpp

@@ -135,11 +135,14 @@ MAKE_PTRARG(Rect2i);
 MAKE_PTRARG_BY_REFERENCE(Vector3);
 MAKE_PTRARG_BY_REFERENCE(Vector3i);
 MAKE_PTRARG(Transform2D);
+MAKE_PTRARG_BY_REFERENCE(Vector4);
+MAKE_PTRARG_BY_REFERENCE(Vector4i);
 MAKE_PTRARG_BY_REFERENCE(Plane);
 MAKE_PTRARG(Quaternion);
 MAKE_PTRARG_BY_REFERENCE(AABB);
 MAKE_PTRARG_BY_REFERENCE(Basis);
 MAKE_PTRARG_BY_REFERENCE(Transform3D);
+MAKE_PTRARG_BY_REFERENCE(Projection);
 MAKE_PTRARG_BY_REFERENCE(Color);
 MAKE_PTRARG(StringName);
 MAKE_PTRARG(NodePath);

+ 3 - 0
include/godot_cpp/core/type_info.hpp

@@ -135,11 +135,14 @@ MAKE_TYPE_INFO(Rect2i, GDNATIVE_VARIANT_TYPE_RECT2I)
 MAKE_TYPE_INFO(Vector3, GDNATIVE_VARIANT_TYPE_VECTOR3)
 MAKE_TYPE_INFO(Vector3i, GDNATIVE_VARIANT_TYPE_VECTOR3I)
 MAKE_TYPE_INFO(Transform2D, GDNATIVE_VARIANT_TYPE_TRANSFORM2D)
+MAKE_TYPE_INFO(Vector4, GDNATIVE_VARIANT_TYPE_VECTOR4)
+MAKE_TYPE_INFO(Vector4i, GDNATIVE_VARIANT_TYPE_VECTOR4I)
 MAKE_TYPE_INFO(Plane, GDNATIVE_VARIANT_TYPE_PLANE)
 MAKE_TYPE_INFO(Quaternion, GDNATIVE_VARIANT_TYPE_QUATERNION)
 MAKE_TYPE_INFO(AABB, GDNATIVE_VARIANT_TYPE_AABB)
 MAKE_TYPE_INFO(Basis, GDNATIVE_VARIANT_TYPE_BASIS)
 MAKE_TYPE_INFO(Transform3D, GDNATIVE_VARIANT_TYPE_TRANSFORM3D)
+MAKE_TYPE_INFO(Projection, GDNATIVE_VARIANT_TYPE_PROJECTION)
 MAKE_TYPE_INFO(Color, GDNATIVE_VARIANT_TYPE_COLOR)
 MAKE_TYPE_INFO(StringName, GDNATIVE_VARIANT_TYPE_STRING_NAME)
 MAKE_TYPE_INFO(NodePath, GDNATIVE_VARIANT_TYPE_NODE_PATH)

+ 16 - 0
include/godot_cpp/templates/hashfuncs.hpp

@@ -45,6 +45,8 @@
 #include <godot_cpp/variant/vector2i.hpp>
 #include <godot_cpp/variant/vector3.hpp>
 #include <godot_cpp/variant/vector3i.hpp>
+#include <godot_cpp/variant/vector4.hpp>
+#include <godot_cpp/variant/vector4i.hpp>
 
 /**
  * Hashing functions
@@ -205,6 +207,13 @@ struct HashMapHasherDefault {
 		h = hash_djb2_one_32(p_vec.y, h);
 		return hash_djb2_one_32(p_vec.z, h);
 	}
+	static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) {
+		uint32_t h = hash_murmur3_one_32(p_vec.x);
+		h = hash_murmur3_one_32(p_vec.y, h);
+		h = hash_murmur3_one_32(p_vec.z, h);
+		h = hash_murmur3_one_32(p_vec.w, h);
+		return hash_fmix32(h);
+	}
 
 	static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) {
 		uint32_t h = hash_djb2_one_float(p_vec.x);
@@ -215,6 +224,13 @@ struct HashMapHasherDefault {
 		h = hash_djb2_one_float(p_vec.y, h);
 		return hash_djb2_one_float(p_vec.z, h);
 	}
+	static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) {
+		uint32_t h = hash_murmur3_one_real(p_vec.x);
+		h = hash_murmur3_one_real(p_vec.y, h);
+		h = hash_murmur3_one_real(p_vec.z, h);
+		h = hash_murmur3_one_real(p_vec.w, h);
+		return hash_fmix32(h);
+	}
 
 	static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
 		uint32_t h = hash_djb2_one_32(p_rect.position.x);

+ 175 - 0
include/godot_cpp/variant/projection.hpp

@@ -0,0 +1,175 @@
+/*************************************************************************/
+/*  projection.hpp                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef GODOT_PROJECTION_HPP
+#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 AABB;
+class Plane;
+class Rect2;
+class Transform3D;
+class Vector2;
+
+class Projection {
+	_FORCE_INLINE_ GDNativeTypePtr _native_ptr() const { return (void *)this; }
+
+	friend class Variant;
+
+public:
+	enum Planes {
+		PLANE_NEAR,
+		PLANE_FAR,
+		PLANE_LEFT,
+		PLANE_TOP,
+		PLANE_RIGHT,
+		PLANE_BOTTOM
+	};
+
+	Vector4 matrix[4];
+
+	_FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const {
+		return matrix[p_axis];
+	}
+
+	_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
+		return matrix[p_axis];
+	}
+
+	float determinant() const;
+	void set_identity();
+	void set_zero();
+	void set_light_bias();
+	void set_depth_correction(bool p_flip_y = true);
+
+	void set_light_atlas_rect(const Rect2 &p_rect);
+	void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
+	void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
+	void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
+	void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
+	void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
+	void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
+	void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
+	void adjust_perspective_znear(real_t p_new_znear);
+
+	static Projection create_depth_correction(bool p_flip_y);
+	static Projection create_light_atlas_rect(const Rect2 &p_rect);
+	static Projection create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
+	static Projection create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
+	static Projection create_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
+	static Projection create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
+	static Projection create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
+	static Projection create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
+	static Projection create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
+	static Projection create_fit_aabb(const AABB &p_aabb);
+	Projection perspective_znear_adjusted(real_t p_new_znear) const;
+	Plane get_projection_plane(Planes p_plane) const;
+	Projection flipped_y() const;
+	Projection jitter_offseted(const Vector2 &p_offset) const;
+
+	static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
+		return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0);
+	}
+
+	real_t get_z_far() const;
+	real_t get_z_near() const;
+	real_t get_aspect() const;
+	real_t get_fov() const;
+	bool is_orthogonal() const;
+
+	Array get_projection_planes(const Transform3D &p_transform) 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;
+
+	void invert();
+	Projection inverse() const;
+
+	Projection operator*(const Projection &p_matrix) const;
+
+	Plane xform4(const Plane &p_vec4) const;
+	_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const;
+
+	Vector4 xform(const Vector4 &p_vec4) const;
+	Vector4 xform_inv(const Vector4 &p_vec4) const;
+
+	operator String() const;
+
+	void scale_translate_to_fit(const AABB &p_aabb);
+	void add_jitter_offset(const Vector2 &p_offset);
+	void make_scale(const Vector3 &p_scale);
+	int get_pixels_per_meter(int p_for_pixel_width) const;
+	operator Transform3D() const;
+
+	void flip_y();
+
+	bool operator==(const 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]) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	bool operator!=(const Projection &p_cam) const {
+		return !(*this == p_cam);
+	}
+
+	float get_lod_multiplier() const;
+
+	Projection();
+	Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w);
+	Projection(const Transform3D &p_transform);
+	~Projection();
+};
+
+Vector3 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];
+	return ret / w;
+}
+
+} // namespace godot
+
+#endif // GODOT_PROJECTION_HPP

+ 9 - 0
include/godot_cpp/variant/variant.hpp

@@ -70,11 +70,14 @@ public:
 		VECTOR3,
 		VECTOR3I,
 		TRANSFORM2D,
+		VECTOR4,
+		VECTOR4I,
 		PLANE,
 		QUATERNION,
 		AABB,
 		BASIS,
 		TRANSFORM3D,
+		PROJECTION,
 
 		// misc types
 		COLOR,
@@ -172,11 +175,14 @@ public:
 	Variant(const Vector3 &v);
 	Variant(const Vector3i &v);
 	Variant(const Transform2D &v);
+	Variant(const Vector4 &v);
+	Variant(const Vector4i &v);
 	Variant(const Plane &v);
 	Variant(const Quaternion &v);
 	Variant(const godot::AABB &v);
 	Variant(const Basis &v);
 	Variant(const Transform3D &v);
+	Variant(const Projection &v);
 	Variant(const Color &v);
 	Variant(const StringName &v);
 	Variant(const NodePath &v);
@@ -212,11 +218,14 @@ public:
 	operator Vector3() const;
 	operator Vector3i() const;
 	operator Transform2D() const;
+	operator Vector4() const;
+	operator Vector4i() const;
 	operator Plane() const;
 	operator Quaternion() const;
 	operator godot::AABB() const;
 	operator Basis() const;
 	operator Transform3D() const;
+	operator Projection() const;
 	operator Color() const;
 	operator StringName() const;
 	operator NodePath() const;

+ 111 - 59
include/godot_cpp/variant/vector2.hpp

@@ -31,6 +31,7 @@
 #ifndef GODOT_VECTOR2_HPP
 #define GODOT_VECTOR2_HPP
 
+#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/core/math.hpp>
 
 namespace godot {
@@ -50,19 +51,39 @@ public:
 	};
 
 	union {
-		real_t x = 0;
-		real_t width;
-	};
-	union {
-		real_t y = 0;
-		real_t height;
+		struct {
+			union {
+				real_t x;
+				real_t width;
+			};
+			union {
+				real_t y;
+				real_t height;
+			};
+		};
+
+		real_t coord[2] = { 0 };
 	};
 
-	inline real_t &operator[](int p_idx) {
-		return p_idx ? y : x;
+	_FORCE_INLINE_ real_t &operator[](int p_idx) {
+		DEV_ASSERT((unsigned int)p_idx < 2);
+		return coord[p_idx];
 	}
-	inline const real_t &operator[](int p_idx) const {
-		return p_idx ? y : x;
+	_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
+		DEV_ASSERT((unsigned int)p_idx < 2);
+		return coord[p_idx];
+	}
+
+	_FORCE_INLINE_ void set_all(const real_t p_value) {
+		x = y = p_value;
+	}
+
+	_FORCE_INLINE_ Vector2::Axis min_axis_index() const {
+		return x < y ? Vector2::AXIS_X : Vector2::AXIS_Y;
+	}
+
+	_FORCE_INLINE_ Vector2::Axis max_axis_index() const {
+		return x < y ? Vector2::AXIS_Y : Vector2::AXIS_X;
 	}
 
 	void normalize();
@@ -71,20 +92,21 @@ public:
 
 	real_t length() const;
 	real_t length_squared() const;
+	Vector2 limit_length(const real_t p_len = 1.0) const;
 
 	Vector2 min(const Vector2 &p_vector2) const {
-		return Vector2(Math::min(x, p_vector2.x), Math::min(y, p_vector2.y));
+		return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y));
 	}
 
 	Vector2 max(const Vector2 &p_vector2) const {
-		return Vector2(Math::max(x, p_vector2.x), Math::max(y, p_vector2.y));
+		return Vector2(MAX(x, p_vector2.x), MAX(y, p_vector2.y));
 	}
 
 	real_t distance_to(const Vector2 &p_vector2) const;
 	real_t distance_squared_to(const Vector2 &p_vector2) const;
 	real_t angle_to(const Vector2 &p_vector2) const;
 	real_t angle_to_point(const Vector2 &p_vector2) const;
-	inline Vector2 direction_to(const Vector2 &p_to) const;
+	_FORCE_INLINE_ Vector2 direction_to(const Vector2 &p_to) const;
 
 	real_t dot(const Vector2 &p_other) const;
 	real_t cross(const Vector2 &p_other) const;
@@ -92,13 +114,13 @@ public:
 	Vector2 posmodv(const Vector2 &p_modv) const;
 	Vector2 project(const Vector2 &p_to) const;
 
-	Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const;
+	Vector2 plane_project(const real_t p_d, const Vector2 &p_vec) const;
 
-	Vector2 clamped(real_t p_len) const;
+	_FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
 
-	inline Vector2 lerp(const Vector2 &p_to, real_t p_weight) const;
-	inline Vector2 slerp(const Vector2 &p_to, real_t p_weight) const;
-	Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const;
 	Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const;
 
 	Vector2 slide(const Vector2 &p_normal) const;
@@ -135,12 +157,13 @@ public:
 	bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); }
 
 	real_t angle() const;
+	static Vector2 from_angle(const real_t p_angle);
 
-	inline Vector2 abs() const {
+	_FORCE_INLINE_ Vector2 abs() const {
 		return Vector2(Math::abs(x), Math::abs(y));
 	}
 
-	Vector2 rotated(real_t p_by) const;
+	Vector2 rotated(const real_t p_by) const;
 	Vector2 orthogonal() const {
 		return Vector2(y, -x);
 	}
@@ -150,95 +173,80 @@ public:
 	Vector2 ceil() const;
 	Vector2 round() const;
 	Vector2 snapped(const Vector2 &p_by) const;
+	Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const;
 	real_t aspect() const { return width / height; }
 
 	operator String() const;
 	operator Vector2i() const;
 
-	inline Vector2() {}
-	inline Vector2(real_t p_x, real_t p_y) {
+	_FORCE_INLINE_ Vector2() {}
+	_FORCE_INLINE_ Vector2(const real_t p_x, const real_t p_y) {
 		x = p_x;
 		y = p_y;
 	}
 };
 
-inline Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const {
+_FORCE_INLINE_ Vector2 Vector2::plane_project(const real_t p_d, const Vector2 &p_vec) const {
 	return p_vec - *this * (dot(p_vec) - p_d);
 }
 
-inline Vector2 operator*(float p_scalar, const Vector2 &p_vec) {
-	return p_vec * (real_t)p_scalar;
-}
-
-inline Vector2 operator*(double p_scalar, const Vector2 &p_vec) {
-	return p_vec * (real_t)p_scalar;
-}
-
-inline Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) {
-	return p_vec * (real_t)p_scalar;
-}
-
-inline Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) {
-	return p_vec * (real_t)p_scalar;
-}
-
-inline Vector2 Vector2::operator+(const Vector2 &p_v) const {
+_FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const {
 	return Vector2(x + p_v.x, y + p_v.y);
 }
 
-inline void Vector2::operator+=(const Vector2 &p_v) {
+_FORCE_INLINE_ void Vector2::operator+=(const Vector2 &p_v) {
 	x += p_v.x;
 	y += p_v.y;
 }
 
-inline Vector2 Vector2::operator-(const Vector2 &p_v) const {
+_FORCE_INLINE_ Vector2 Vector2::operator-(const Vector2 &p_v) const {
 	return Vector2(x - p_v.x, y - p_v.y);
 }
 
-inline void Vector2::operator-=(const Vector2 &p_v) {
+_FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) {
 	x -= p_v.x;
 	y -= p_v.y;
 }
 
-inline Vector2 Vector2::operator*(const Vector2 &p_v1) const {
+_FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const {
 	return Vector2(x * p_v1.x, y * p_v1.y);
 }
 
-inline Vector2 Vector2::operator*(const real_t &rvalue) const {
+_FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const {
 	return Vector2(x * rvalue, y * rvalue);
 }
 
-inline void Vector2::operator*=(const real_t &rvalue) {
+_FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) {
 	x *= rvalue;
 	y *= rvalue;
 }
 
-inline Vector2 Vector2::operator/(const Vector2 &p_v1) const {
+_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const {
 	return Vector2(x / p_v1.x, y / p_v1.y);
 }
 
-inline Vector2 Vector2::operator/(const real_t &rvalue) const {
+_FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const {
 	return Vector2(x / rvalue, y / rvalue);
 }
 
-inline void Vector2::operator/=(const real_t &rvalue) {
+_FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) {
 	x /= rvalue;
 	y /= rvalue;
 }
 
-inline Vector2 Vector2::operator-() const {
+_FORCE_INLINE_ Vector2 Vector2::operator-() const {
 	return Vector2(-x, -y);
 }
 
-inline bool Vector2::operator==(const Vector2 &p_vec2) const {
+_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
 	return x == p_vec2.x && y == p_vec2.y;
 }
 
-inline bool Vector2::operator!=(const Vector2 &p_vec2) const {
+_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
 	return x != p_vec2.x || y != p_vec2.y;
 }
 
-Vector2 Vector2::lerp(const Vector2 &p_to, real_t p_weight) const {
+Vector2 Vector2::lerp(const Vector2 &p_to, const real_t p_weight) const {
 	Vector2 res = *this;
 
 	res.x += (p_weight * (p_to.x - x));
@@ -247,12 +255,37 @@ Vector2 Vector2::lerp(const Vector2 &p_to, real_t p_weight) const {
 	return res;
 }
 
-Vector2 Vector2::slerp(const Vector2 &p_to, real_t p_weight) const {
-#ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!is_normalized(), Vector2());
-#endif
-	real_t theta = angle_to(p_to);
-	return rotated(theta * p_weight);
+Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const {
+	real_t start_length_sq = length_squared();
+	real_t end_length_sq = p_to.length_squared();
+	if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) {
+		// Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
+		return lerp(p_to, p_weight);
+	}
+	real_t start_length = Math::sqrt(start_length_sq);
+	real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight);
+	real_t angle = angle_to(p_to);
+	return rotated(angle * p_weight) * (result_length / start_length);
+}
+
+Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const {
+	Vector2 res = *this;
+	res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
+	res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
+	return res;
+}
+
+Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
+	Vector2 res = *this;
+
+	/* Formula from Wikipedia article on Bezier curves. */
+	real_t omt = (1.0 - p_t);
+	real_t omt2 = omt * omt;
+	real_t omt3 = omt2 * omt;
+	real_t t2 = p_t * p_t;
+	real_t t3 = t2 * p_t;
+
+	return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
 }
 
 Vector2 Vector2::direction_to(const Vector2 &p_to) const {
@@ -261,6 +294,25 @@ Vector2 Vector2::direction_to(const Vector2 &p_to) const {
 	return ret;
 }
 
+// Multiplication operators required to workaround issues with LLVM using implicit conversion
+// to Vector2i instead for integers where it should not.
+
+_FORCE_INLINE_ Vector2 operator*(const float p_scalar, const Vector2 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(const double p_scalar, const Vector2 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(const int32_t p_scalar, const Vector2 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(const int64_t p_scalar, const Vector2 &p_vec) {
+	return p_vec * p_scalar;
+}
+
 typedef Vector2 Size2;
 typedef Vector2 Point2;
 

+ 51 - 24
include/godot_cpp/variant/vector2i.hpp

@@ -31,6 +31,7 @@
 #ifndef GODOT_VECTOR2I_HPP
 #define GODOT_VECTOR2I_HPP
 
+#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/core/math.hpp>
 
 namespace godot {
@@ -50,19 +51,43 @@ public:
 	};
 
 	union {
-		int32_t x = 0;
-		int32_t width;
-	};
-	union {
-		int32_t y = 0;
-		int32_t height;
+		struct {
+			union {
+				int32_t x;
+				int32_t width;
+			};
+			union {
+				int32_t y;
+				int32_t height;
+			};
+		};
+
+		int32_t coord[2] = { 0 };
 	};
 
-	inline int32_t &operator[](int p_idx) {
-		return p_idx ? y : x;
+	_FORCE_INLINE_ int32_t &operator[](int p_idx) {
+		DEV_ASSERT((unsigned int)p_idx < 2);
+		return coord[p_idx];
+	}
+	_FORCE_INLINE_ const int32_t &operator[](int p_idx) const {
+		DEV_ASSERT((unsigned int)p_idx < 2);
+		return coord[p_idx];
+	}
+
+	_FORCE_INLINE_ Vector2i::Axis min_axis_index() const {
+		return x < y ? Vector2i::AXIS_X : Vector2i::AXIS_Y;
+	}
+
+	_FORCE_INLINE_ Vector2i::Axis max_axis_index() const {
+		return x < y ? Vector2i::AXIS_Y : Vector2i::AXIS_X;
 	}
-	inline const int32_t &operator[](int p_idx) const {
-		return p_idx ? y : x;
+
+	Vector2i min(const Vector2i &p_vector2i) const {
+		return Vector2i(MIN(x, p_vector2i.x), MIN(y, p_vector2i.y));
+	}
+
+	Vector2i max(const Vector2i &p_vector2i) const {
+		return Vector2i(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y));
 	}
 
 	Vector2i operator+(const Vector2i &p_v) const;
@@ -92,38 +117,40 @@ public:
 	bool operator==(const Vector2i &p_vec2) const;
 	bool operator!=(const Vector2i &p_vec2) const;
 
+	int64_t length_squared() const;
+	double length() const;
+
 	real_t aspect() const { return width / (real_t)height; }
-	Vector2i sign() const { return Vector2i(Math::sign(x), Math::sign(y)); }
-	Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); }
+	Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); }
+	Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); }
+	Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const;
 
 	operator String() const;
 	operator Vector2() const;
 
 	inline Vector2i() {}
-	inline Vector2i(int32_t p_x, int32_t p_y) {
+	inline Vector2i(const int32_t p_x, const int32_t p_y) {
 		x = p_x;
 		y = p_y;
 	}
 };
 
-inline Vector2i operator*(const int32_t &p_scalar, const Vector2i &p_vector) {
+// Multiplication operators required to workaround issues with LLVM using implicit conversion.
+
+_FORCE_INLINE_ Vector2i operator*(const int32_t p_scalar, const Vector2i &p_vector) {
 	return p_vector * p_scalar;
 }
 
-inline Vector2i operator*(const int64_t &p_scalar, const Vector2i &p_vector) {
-	return p_vector * (int32_t)p_scalar;
+_FORCE_INLINE_ Vector2i operator*(const int64_t p_scalar, const Vector2i &p_vector) {
+	return p_vector * p_scalar;
 }
 
-inline Vector2i operator*(const float &p_scalar, const Vector2i &p_vector) {
-	float x = (float)p_vector.x * p_scalar;
-	float y = (float)p_vector.y * p_scalar;
-	return Vector2i((int32_t)round(x), (int32_t)round(y));
+_FORCE_INLINE_ Vector2i operator*(const float p_scalar, const Vector2i &p_vector) {
+	return p_vector * p_scalar;
 }
 
-inline Vector2i operator*(const double &p_scalar, const Vector2i &p_vector) {
-	double x = (double)p_vector.x * p_scalar;
-	double y = (double)p_vector.y * p_scalar;
-	return Vector2i((int32_t)round(x), (int32_t)round(y));
+_FORCE_INLINE_ Vector2i operator*(const double p_scalar, const Vector2i &p_vector) {
+	return p_vector * p_scalar;
 }
 
 typedef Vector2i Size2i;

+ 160 - 89
include/godot_cpp/variant/vector3.hpp

@@ -31,12 +31,14 @@
 #ifndef GODOT_VECTOR3_HPP
 #define GODOT_VECTOR3_HPP
 
+#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/core/math.hpp>
 
 namespace godot {
 
 class Basis;
 class String;
+class Vector2;
 class Vector3i;
 
 class Vector3 {
@@ -61,117 +63,135 @@ public:
 		real_t coord[3] = { 0 };
 	};
 
-	inline const real_t &operator[](int p_axis) const {
+	_FORCE_INLINE_ const real_t &operator[](const int p_axis) const {
+		DEV_ASSERT((unsigned int)p_axis < 3);
 		return coord[p_axis];
 	}
 
-	inline real_t &operator[](int p_axis) {
+	_FORCE_INLINE_ real_t &operator[](const int p_axis) {
+		DEV_ASSERT((unsigned int)p_axis < 3);
 		return coord[p_axis];
 	}
 
-	void set_axis(int p_axis, real_t p_value);
-	real_t get_axis(int p_axis) const;
+	void set_axis(const int p_axis, const real_t p_value);
+	real_t get_axis(const int p_axis) const;
 
-	int min_axis() const;
-	int max_axis() const;
+	_FORCE_INLINE_ void set_all(const real_t p_value) {
+		x = y = z = p_value;
+	}
+
+	_FORCE_INLINE_ Vector3::Axis min_axis_index() const {
+		return x < y ? (x < z ? Vector3::AXIS_X : Vector3::AXIS_Z) : (y < z ? Vector3::AXIS_Y : Vector3::AXIS_Z);
+	}
 
-	inline real_t length() const;
-	inline real_t length_squared() const;
+	_FORCE_INLINE_ Vector3::Axis max_axis_index() const {
+		return x < y ? (y < z ? Vector3::AXIS_Z : Vector3::AXIS_Y) : (x < z ? Vector3::AXIS_Z : Vector3::AXIS_X);
+	}
 
-	inline void normalize();
-	inline Vector3 normalized() const;
-	inline bool is_normalized() const;
-	inline Vector3 inverse() const;
+	_FORCE_INLINE_ real_t length() const;
+	_FORCE_INLINE_ real_t length_squared() const;
 
-	inline void zero();
+	_FORCE_INLINE_ void normalize();
+	_FORCE_INLINE_ Vector3 normalized() const;
+	_FORCE_INLINE_ bool is_normalized() const;
+	_FORCE_INLINE_ Vector3 inverse() const;
+	Vector3 limit_length(const real_t p_len = 1.0) const;
 
-	void snap(Vector3 p_val);
-	Vector3 snapped(Vector3 p_val) const;
+	_FORCE_INLINE_ void zero();
 
-	void rotate(const Vector3 &p_axis, real_t p_phi);
-	Vector3 rotated(const Vector3 &p_axis, real_t p_phi) const;
+	void snap(const Vector3 p_val);
+	Vector3 snapped(const Vector3 p_val) const;
+
+	void rotate(const Vector3 &p_axis, const real_t p_angle);
+	Vector3 rotated(const Vector3 &p_axis, const real_t p_angle) const;
 
 	/* Static Methods between 2 vector3s */
 
-	inline Vector3 lerp(const Vector3 &p_to, real_t p_weight) const;
-	inline Vector3 slerp(const Vector3 &p_to, real_t p_weight) const;
-	Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const;
+	_FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
+
 	Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const;
 
-	inline Vector3 cross(const Vector3 &p_b) const;
-	inline real_t dot(const Vector3 &p_b) const;
-	Basis outer(const Vector3 &p_b) const;
-	Basis to_diagonal_matrix() const;
+	Vector2 octahedron_encode() const;
+	static Vector3 octahedron_decode(const Vector2 &p_oct);
+
+	_FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const;
+	_FORCE_INLINE_ real_t dot(const Vector3 &p_with) const;
+	Basis outer(const Vector3 &p_with) const;
 
-	inline Vector3 abs() const;
-	inline Vector3 floor() const;
-	inline Vector3 sign() const;
-	inline Vector3 ceil() const;
-	inline Vector3 round() const;
+	_FORCE_INLINE_ Vector3 abs() const;
+	_FORCE_INLINE_ Vector3 floor() const;
+	_FORCE_INLINE_ Vector3 sign() const;
+	_FORCE_INLINE_ Vector3 ceil() const;
+	_FORCE_INLINE_ Vector3 round() const;
+	Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const;
 
-	inline real_t distance_to(const Vector3 &p_to) const;
-	inline real_t distance_squared_to(const Vector3 &p_to) const;
+	_FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const;
+	_FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const;
 
-	inline Vector3 posmod(const real_t p_mod) const;
-	inline Vector3 posmodv(const Vector3 &p_modv) const;
-	inline Vector3 project(const Vector3 &p_to) const;
+	_FORCE_INLINE_ Vector3 posmod(const real_t p_mod) const;
+	_FORCE_INLINE_ Vector3 posmodv(const Vector3 &p_modv) const;
+	_FORCE_INLINE_ Vector3 project(const Vector3 &p_to) const;
 
-	inline real_t angle_to(const Vector3 &p_to) const;
-	inline Vector3 direction_to(const Vector3 &p_to) const;
+	_FORCE_INLINE_ real_t angle_to(const Vector3 &p_to) const;
+	_FORCE_INLINE_ real_t signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const;
+	_FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_to) const;
 
-	inline Vector3 slide(const Vector3 &p_normal) const;
-	inline Vector3 bounce(const Vector3 &p_normal) const;
-	inline Vector3 reflect(const Vector3 &p_normal) const;
+	_FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const;
+	_FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const;
+	_FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const;
 
 	bool is_equal_approx(const Vector3 &p_v) const;
 
 	/* Operators */
 
-	inline Vector3 &operator+=(const Vector3 &p_v);
-	inline Vector3 operator+(const Vector3 &p_v) const;
-	inline Vector3 &operator-=(const Vector3 &p_v);
-	inline Vector3 operator-(const Vector3 &p_v) const;
-	inline Vector3 &operator*=(const Vector3 &p_v);
-	inline Vector3 operator*(const Vector3 &p_v) const;
-	inline Vector3 &operator/=(const Vector3 &p_v);
-	inline Vector3 operator/(const Vector3 &p_v) const;
-
-	inline Vector3 &operator*=(real_t p_scalar);
-	inline Vector3 operator*(real_t p_scalar) const;
-	inline Vector3 &operator/=(real_t p_scalar);
-	inline Vector3 operator/(real_t p_scalar) const;
-
-	inline Vector3 operator-() const;
-
-	inline bool operator==(const Vector3 &p_v) const;
-	inline bool operator!=(const Vector3 &p_v) const;
-	inline bool operator<(const Vector3 &p_v) const;
-	inline bool operator<=(const Vector3 &p_v) const;
-	inline bool operator>(const Vector3 &p_v) const;
-	inline bool operator>=(const Vector3 &p_v) const;
+	_FORCE_INLINE_ Vector3 &operator+=(const Vector3 &p_v);
+	_FORCE_INLINE_ Vector3 operator+(const Vector3 &p_v) const;
+	_FORCE_INLINE_ Vector3 &operator-=(const Vector3 &p_v);
+	_FORCE_INLINE_ Vector3 operator-(const Vector3 &p_v) const;
+	_FORCE_INLINE_ Vector3 &operator*=(const Vector3 &p_v);
+	_FORCE_INLINE_ Vector3 operator*(const Vector3 &p_v) const;
+	_FORCE_INLINE_ Vector3 &operator/=(const Vector3 &p_v);
+	_FORCE_INLINE_ Vector3 operator/(const Vector3 &p_v) const;
+
+	_FORCE_INLINE_ Vector3 &operator*=(const real_t p_scalar);
+	_FORCE_INLINE_ Vector3 operator*(const real_t p_scalar) const;
+	_FORCE_INLINE_ Vector3 &operator/=(const real_t p_scalar);
+	_FORCE_INLINE_ Vector3 operator/(const real_t p_scalar) const;
+
+	_FORCE_INLINE_ Vector3 operator-() const;
+
+	_FORCE_INLINE_ bool operator==(const Vector3 &p_v) const;
+	_FORCE_INLINE_ bool operator!=(const Vector3 &p_v) const;
+	_FORCE_INLINE_ bool operator<(const Vector3 &p_v) const;
+	_FORCE_INLINE_ bool operator<=(const Vector3 &p_v) const;
+	_FORCE_INLINE_ bool operator>(const Vector3 &p_v) const;
+	_FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const;
 
 	operator String() const;
 	operator Vector3i() const;
 
-	inline Vector3() {}
-	inline Vector3(real_t p_x, real_t p_y, real_t p_z) {
+	_FORCE_INLINE_ Vector3() {}
+	_FORCE_INLINE_ Vector3(const real_t p_x, const real_t p_y, const real_t p_z) {
 		x = p_x;
 		y = p_y;
 		z = p_z;
 	}
 };
 
-Vector3 Vector3::cross(const Vector3 &p_b) const {
+Vector3 Vector3::cross(const Vector3 &p_with) const {
 	Vector3 ret(
-			(y * p_b.z) - (z * p_b.y),
-			(z * p_b.x) - (x * p_b.z),
-			(x * p_b.y) - (y * p_b.x));
+			(y * p_with.z) - (z * p_with.y),
+			(z * p_with.x) - (x * p_with.z),
+			(x * p_with.y) - (y * p_with.x));
 
 	return ret;
 }
 
-real_t Vector3::dot(const Vector3 &p_b) const {
-	return x * p_b.x + y * p_b.y + z * p_b.z;
+real_t Vector3::dot(const Vector3 &p_with) const {
+	return x * p_with.x + y * p_with.y + z * p_with.z;
 }
 
 Vector3 Vector3::abs() const {
@@ -179,7 +199,7 @@ Vector3 Vector3::abs() const {
 }
 
 Vector3 Vector3::sign() const {
-	return Vector3(Math::sign(x), Math::sign(y), Math::sign(z));
+	return Vector3(SIGN(x), SIGN(y), SIGN(z));
 }
 
 Vector3 Vector3::floor() const {
@@ -194,16 +214,45 @@ Vector3 Vector3::round() const {
 	return Vector3(Math::round(x), Math::round(y), Math::round(z));
 }
 
-Vector3 Vector3::lerp(const Vector3 &p_to, real_t p_weight) const {
+Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const {
 	return Vector3(
 			x + (p_weight * (p_to.x - x)),
 			y + (p_weight * (p_to.y - y)),
 			z + (p_weight * (p_to.z - z)));
 }
 
-Vector3 Vector3::slerp(const Vector3 &p_to, real_t p_weight) const {
-	real_t theta = angle_to(p_to);
-	return rotated(cross(p_to).normalized(), theta * p_weight);
+Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const {
+	real_t start_length_sq = length_squared();
+	real_t end_length_sq = p_to.length_squared();
+	if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) {
+		// Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
+		return lerp(p_to, p_weight);
+	}
+	real_t start_length = Math::sqrt(start_length_sq);
+	real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight);
+	real_t angle = angle_to(p_to);
+	return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length);
+}
+
+Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const {
+	Vector3 res = *this;
+	res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
+	res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
+	res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight);
+	return res;
+}
+
+Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const {
+	Vector3 res = *this;
+
+	/* Formula from Wikipedia article on Bezier curves. */
+	real_t omt = (1.0 - p_t);
+	real_t omt2 = omt * omt;
+	real_t omt3 = omt2 * omt;
+	real_t t2 = p_t * p_t;
+	real_t t3 = t2 * p_t;
+
+	return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
 }
 
 real_t Vector3::distance_to(const Vector3 &p_to) const {
@@ -230,6 +279,13 @@ real_t Vector3::angle_to(const Vector3 &p_to) const {
 	return Math::atan2(cross(p_to).length(), dot(p_to));
 }
 
+real_t Vector3::signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const {
+	Vector3 cross_to = cross(p_to);
+	real_t unsigned_angle = Math::atan2(cross_to.length(), dot(p_to));
+	real_t sign = cross_to.dot(p_axis);
+	return (sign < 0) ? -unsigned_angle : unsigned_angle;
+}
+
 Vector3 Vector3::direction_to(const Vector3 &p_to) const {
 	Vector3 ret(p_to.x - x, p_to.y - y, p_to.z - z);
 	ret.normalize();
@@ -282,29 +338,44 @@ Vector3 Vector3::operator/(const Vector3 &p_v) const {
 	return Vector3(x / p_v.x, y / p_v.y, z / p_v.z);
 }
 
-Vector3 &Vector3::operator*=(real_t p_scalar) {
+Vector3 &Vector3::operator*=(const real_t p_scalar) {
 	x *= p_scalar;
 	y *= p_scalar;
 	z *= p_scalar;
 	return *this;
 }
 
-inline Vector3 operator*(real_t p_scalar, const Vector3 &p_vec) {
+// Multiplication operators required to workaround issues with LLVM using implicit conversion
+// to Vector3i instead for integers where it should not.
+
+_FORCE_INLINE_ Vector3 operator*(const float p_scalar, const Vector3 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector3 operator*(const double p_scalar, const Vector3 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector3 operator*(const int32_t p_scalar, const Vector3 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector3 operator*(const int64_t p_scalar, const Vector3 &p_vec) {
 	return p_vec * p_scalar;
 }
 
-Vector3 Vector3::operator*(real_t p_scalar) const {
+Vector3 Vector3::operator*(const real_t p_scalar) const {
 	return Vector3(x * p_scalar, y * p_scalar, z * p_scalar);
 }
 
-Vector3 &Vector3::operator/=(real_t p_scalar) {
+Vector3 &Vector3::operator/=(const real_t p_scalar) {
 	x /= p_scalar;
 	y /= p_scalar;
 	z /= p_scalar;
 	return *this;
 }
 
-Vector3 Vector3::operator/(real_t p_scalar) const {
+Vector3 Vector3::operator/(const real_t p_scalar) const {
 	return Vector3(x / p_scalar, y / p_scalar, z / p_scalar);
 }
 
@@ -360,11 +431,11 @@ bool Vector3::operator>=(const Vector3 &p_v) const {
 	return x > p_v.x;
 }
 
-inline Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) {
+_FORCE_INLINE_ Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) {
 	return p_a.cross(p_b);
 }
 
-inline real_t vec3_dot(const Vector3 &p_a, const Vector3 &p_b) {
+_FORCE_INLINE_ real_t vec3_dot(const Vector3 &p_a, const Vector3 &p_b) {
 	return p_a.dot(p_b);
 }
 
@@ -386,8 +457,8 @@ real_t Vector3::length_squared() const {
 
 void Vector3::normalize() {
 	real_t lengthsq = length_squared();
-	if (lengthsq == (real_t)0.0) {
-		x = y = z = (real_t)0.0;
+	if (lengthsq == 0) {
+		x = y = z = 0;
 	} else {
 		real_t length = Math::sqrt(lengthsq);
 		x /= length;
@@ -404,21 +475,21 @@ Vector3 Vector3::normalized() const {
 
 bool Vector3::is_normalized() const {
 	// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
-	return Math::is_equal_approx(length_squared(), (real_t)1.0, (real_t)UNIT_EPSILON);
+	return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON);
 }
 
 Vector3 Vector3::inverse() const {
-	return Vector3((real_t)1.0 / x, (real_t)1.0 / y, (real_t)1.0 / z);
+	return Vector3(1.0f / x, 1.0f / y, 1.0f / z);
 }
 
 void Vector3::zero() {
-	x = y = z = (real_t)0.0;
+	x = y = z = 0;
 }
 
 // slide returns the component of the vector along the given plane, specified by its normal vector.
 Vector3 Vector3::slide(const Vector3 &p_normal) const {
 #ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector3());
+	ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 must be normalized.");
 #endif
 	return *this - p_normal * this->dot(p_normal);
 }
@@ -429,9 +500,9 @@ Vector3 Vector3::bounce(const Vector3 &p_normal) const {
 
 Vector3 Vector3::reflect(const Vector3 &p_normal) const {
 #ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector3());
+	ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 must be normalized.");
 #endif
-	return 2.0 * p_normal * this->dot(p_normal) - *this;
+	return 2.0f * p_normal * this->dot(p_normal) - *this;
 }
 
 } // namespace godot

+ 77 - 48
include/godot_cpp/variant/vector3i.hpp

@@ -31,6 +31,7 @@
 #ifndef GODOT_VECTOR3I_HPP
 #define GODOT_VECTOR3I_HPP
 
+#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/core/math.hpp>
 
 namespace godot {
@@ -60,71 +61,85 @@ public:
 		int32_t coord[3] = { 0 };
 	};
 
-	inline const int32_t &operator[](int p_axis) const {
+	_FORCE_INLINE_ const int32_t &operator[](const int p_axis) const {
+		DEV_ASSERT((unsigned int)p_axis < 3);
 		return coord[p_axis];
 	}
 
-	inline int32_t &operator[](int p_axis) {
+	_FORCE_INLINE_ int32_t &operator[](const int p_axis) {
+		DEV_ASSERT((unsigned int)p_axis < 3);
 		return coord[p_axis];
 	}
 
-	void set_axis(int p_axis, int32_t p_value);
-	int32_t get_axis(int p_axis) const;
+	void set_axis(const int p_axis, const int32_t p_value);
+	int32_t get_axis(const int p_axis) const;
 
-	int min_axis() const;
-	int max_axis() const;
+	Vector3i::Axis min_axis_index() const;
+	Vector3i::Axis max_axis_index() const;
 
-	inline void zero();
+	_FORCE_INLINE_ int64_t length_squared() const;
+	_FORCE_INLINE_ double length() const;
 
-	inline Vector3i abs() const;
-	inline Vector3i sign() const;
+	_FORCE_INLINE_ void zero();
+
+	_FORCE_INLINE_ Vector3i abs() const;
+	_FORCE_INLINE_ Vector3i sign() const;
+	Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const;
 
 	/* Operators */
 
-	inline Vector3i &operator+=(const Vector3i &p_v);
-	inline Vector3i operator+(const Vector3i &p_v) const;
-	inline Vector3i &operator-=(const Vector3i &p_v);
-	inline Vector3i operator-(const Vector3i &p_v) const;
-	inline Vector3i &operator*=(const Vector3i &p_v);
-	inline Vector3i operator*(const Vector3i &p_v) const;
-	inline Vector3i &operator/=(const Vector3i &p_v);
-	inline Vector3i operator/(const Vector3i &p_v) const;
-	inline Vector3i &operator%=(const Vector3i &p_v);
-	inline Vector3i operator%(const Vector3i &p_v) const;
-
-	inline Vector3i &operator*=(int32_t p_scalar);
-	inline Vector3i operator*(int32_t p_scalar) const;
-	inline Vector3i &operator/=(int32_t p_scalar);
-	inline Vector3i operator/(int32_t p_scalar) const;
-	inline Vector3i &operator%=(int32_t p_scalar);
-	inline Vector3i operator%(int32_t p_scalar) const;
-
-	inline Vector3i operator-() const;
-
-	inline bool operator==(const Vector3i &p_v) const;
-	inline bool operator!=(const Vector3i &p_v) const;
-	inline bool operator<(const Vector3i &p_v) const;
-	inline bool operator<=(const Vector3i &p_v) const;
-	inline bool operator>(const Vector3i &p_v) const;
-	inline bool operator>=(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator+=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator+(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator-=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator-(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator*=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator%=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator%(const Vector3i &p_v) const;
+
+	_FORCE_INLINE_ Vector3i &operator*=(const int32_t p_scalar);
+	_FORCE_INLINE_ Vector3i operator*(const int32_t p_scalar) const;
+	_FORCE_INLINE_ Vector3i &operator/=(const int32_t p_scalar);
+	_FORCE_INLINE_ Vector3i operator/(const int32_t p_scalar) const;
+	_FORCE_INLINE_ Vector3i &operator%=(const int32_t p_scalar);
+	_FORCE_INLINE_ Vector3i operator%(const int32_t p_scalar) const;
+
+	_FORCE_INLINE_ Vector3i operator-() const;
+
+	_FORCE_INLINE_ bool operator==(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator!=(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator<(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator<=(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator>(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator>=(const Vector3i &p_v) const;
 
 	operator String() const;
 	operator Vector3() const;
 
-	inline Vector3i() {}
-	inline Vector3i(int32_t p_x, int32_t p_y, int32_t p_z) {
+	_FORCE_INLINE_ Vector3i() {}
+	_FORCE_INLINE_ Vector3i(const int32_t p_x, const int32_t p_y, const int32_t p_z) {
 		x = p_x;
 		y = p_y;
 		z = p_z;
 	}
 };
 
+int64_t Vector3i::length_squared() const {
+	return x * (int64_t)x + y * (int64_t)y + z * (int64_t)z;
+}
+
+double Vector3i::length() const {
+	return Math::sqrt((double)length_squared());
+}
+
 Vector3i Vector3i::abs() const {
-	return Vector3i(Math::abs(x), Math::abs(y), Math::abs(z));
+	return Vector3i(ABS(x), ABS(y), ABS(z));
 }
 
 Vector3i Vector3i::sign() const {
-	return Vector3i(Math::sign(x), Math::sign(y), Math::sign(z));
+	return Vector3i(SIGN(x), SIGN(y), SIGN(z));
 }
 
 /* Operators */
@@ -184,40 +199,54 @@ Vector3i Vector3i::operator%(const Vector3i &p_v) const {
 	return Vector3i(x % p_v.x, y % p_v.y, z % p_v.z);
 }
 
-Vector3i &Vector3i::operator*=(int32_t p_scalar) {
+Vector3i &Vector3i::operator*=(const int32_t p_scalar) {
 	x *= p_scalar;
 	y *= p_scalar;
 	z *= p_scalar;
 	return *this;
 }
 
-inline Vector3i operator*(int32_t p_scalar, const Vector3i &p_vec) {
-	return p_vec * p_scalar;
+Vector3i Vector3i::operator*(const int32_t p_scalar) const {
+	return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar);
 }
 
-Vector3i Vector3i::operator*(int32_t p_scalar) const {
-	return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar);
+// Multiplication operators required to workaround issues with LLVM using implicit conversion.
+
+_FORCE_INLINE_ Vector3i operator*(const int32_t p_scalar, const Vector3i &p_vector) {
+	return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector3i operator*(const int64_t p_scalar, const Vector3i &p_vector) {
+	return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector3i operator*(const float p_scalar, const Vector3i &p_vector) {
+	return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector3i operator*(const double p_scalar, const Vector3i &p_vector) {
+	return p_vector * p_scalar;
 }
 
-Vector3i &Vector3i::operator/=(int32_t p_scalar) {
+Vector3i &Vector3i::operator/=(const int32_t p_scalar) {
 	x /= p_scalar;
 	y /= p_scalar;
 	z /= p_scalar;
 	return *this;
 }
 
-Vector3i Vector3i::operator/(int32_t p_scalar) const {
+Vector3i Vector3i::operator/(const int32_t p_scalar) const {
 	return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar);
 }
 
-Vector3i &Vector3i::operator%=(int32_t p_scalar) {
+Vector3i &Vector3i::operator%=(const int32_t p_scalar) {
 	x %= p_scalar;
 	y %= p_scalar;
 	z %= p_scalar;
 	return *this;
 }
 
-Vector3i Vector3i::operator%(int32_t p_scalar) const {
+Vector3i Vector3i::operator%(const int32_t p_scalar) const {
 	return Vector3i(x % p_scalar, y % p_scalar, z % p_scalar);
 }
 

+ 297 - 0
include/godot_cpp/variant/vector4.hpp

@@ -0,0 +1,297 @@
+/*************************************************************************/
+/*  vector4.hpp                                                          */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef GODOT_VECTOR4_HPP
+#define GODOT_VECTOR4_HPP
+
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/math.hpp>
+
+namespace godot {
+
+class String;
+
+class Vector4 {
+	_FORCE_INLINE_ GDNativeTypePtr _native_ptr() const { return (void *)this; }
+
+	friend class Variant;
+
+public:
+	enum Axis {
+		AXIS_X,
+		AXIS_Y,
+		AXIS_Z,
+		AXIS_W,
+	};
+
+	union {
+		struct {
+			real_t x;
+			real_t y;
+			real_t z;
+			real_t w;
+		};
+		real_t components[4] = { 0, 0, 0, 0 };
+	};
+
+	_FORCE_INLINE_ real_t &operator[](int idx) {
+		return components[idx];
+	}
+	_FORCE_INLINE_ const real_t &operator[](int idx) const {
+		return components[idx];
+	}
+	_FORCE_INLINE_ real_t length_squared() const;
+	bool is_equal_approx(const Vector4 &p_vec4) const;
+	real_t length() const;
+	void normalize();
+	Vector4 normalized() const;
+	bool is_normalized() const;
+	Vector4 abs() const;
+	Vector4 sign() const;
+
+	Vector4::Axis min_axis_index() const;
+	Vector4::Axis max_axis_index() const;
+	Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const;
+
+	Vector4 inverse() const;
+	_FORCE_INLINE_ real_t dot(const Vector4 &p_vec4) const;
+
+	_FORCE_INLINE_ void operator+=(const Vector4 &p_vec4);
+	_FORCE_INLINE_ void operator-=(const Vector4 &p_vec4);
+	_FORCE_INLINE_ void operator*=(const Vector4 &p_vec4);
+	_FORCE_INLINE_ void operator/=(const Vector4 &p_vec4);
+	_FORCE_INLINE_ void operator*=(const real_t &s);
+	_FORCE_INLINE_ void operator/=(const real_t &s);
+	_FORCE_INLINE_ Vector4 operator+(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ Vector4 operator-(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ Vector4 operator*(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ Vector4 operator/(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ Vector4 operator-() const;
+	_FORCE_INLINE_ Vector4 operator*(const real_t &s) const;
+	_FORCE_INLINE_ Vector4 operator/(const real_t &s) const;
+
+	_FORCE_INLINE_ bool operator==(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ bool operator!=(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ bool operator>(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ bool operator<(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ bool operator>=(const Vector4 &p_vec4) const;
+	_FORCE_INLINE_ bool operator<=(const Vector4 &p_vec4) const;
+
+	operator String() const;
+
+	_FORCE_INLINE_ Vector4() {}
+
+	_FORCE_INLINE_ Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) :
+			x(p_x),
+			y(p_y),
+			z(p_z),
+			w(p_w) {
+	}
+
+	Vector4(const Vector4 &p_vec4) :
+			x(p_vec4.x),
+			y(p_vec4.y),
+			z(p_vec4.z),
+			w(p_vec4.w) {
+	}
+
+	void operator=(const Vector4 &p_vec4) {
+		x = p_vec4.x;
+		y = p_vec4.y;
+		z = p_vec4.z;
+		w = p_vec4.w;
+	}
+};
+
+real_t Vector4::dot(const Vector4 &p_vec4) const {
+	return x * p_vec4.x + y * p_vec4.y + z * p_vec4.z + w * p_vec4.w;
+}
+
+real_t Vector4::length_squared() const {
+	return dot(*this);
+}
+
+void Vector4::operator+=(const Vector4 &p_vec4) {
+	x += p_vec4.x;
+	y += p_vec4.y;
+	z += p_vec4.z;
+	w += p_vec4.w;
+}
+
+void Vector4::operator-=(const Vector4 &p_vec4) {
+	x -= p_vec4.x;
+	y -= p_vec4.y;
+	z -= p_vec4.z;
+	w -= p_vec4.w;
+}
+
+void Vector4::operator*=(const Vector4 &p_vec4) {
+	x *= p_vec4.x;
+	y *= p_vec4.y;
+	z *= p_vec4.z;
+	w *= p_vec4.w;
+}
+
+void Vector4::operator/=(const Vector4 &p_vec4) {
+	x /= p_vec4.x;
+	y /= p_vec4.y;
+	z /= p_vec4.z;
+	w /= p_vec4.w;
+}
+void Vector4::operator*=(const real_t &s) {
+	x *= s;
+	y *= s;
+	z *= s;
+	w *= s;
+}
+
+void Vector4::operator/=(const real_t &s) {
+	*this *= 1.0f / s;
+}
+
+Vector4 Vector4::operator+(const Vector4 &p_vec4) const {
+	return Vector4(x + p_vec4.x, y + p_vec4.y, z + p_vec4.z, w + p_vec4.w);
+}
+
+Vector4 Vector4::operator-(const Vector4 &p_vec4) const {
+	return Vector4(x - p_vec4.x, y - p_vec4.y, z - p_vec4.z, w - p_vec4.w);
+}
+
+Vector4 Vector4::operator*(const Vector4 &p_vec4) const {
+	return Vector4(x * p_vec4.x, y * p_vec4.y, z * p_vec4.z, w * p_vec4.w);
+}
+
+Vector4 Vector4::operator/(const Vector4 &p_vec4) const {
+	return Vector4(x / p_vec4.x, y / p_vec4.y, z / p_vec4.z, w / p_vec4.w);
+}
+
+Vector4 Vector4::operator-() const {
+	return Vector4(x, y, z, w);
+}
+
+Vector4 Vector4::operator*(const real_t &s) const {
+	return Vector4(x * s, y * s, z * s, w * s);
+}
+
+Vector4 Vector4::operator/(const real_t &s) const {
+	return *this * (1.0f / s);
+}
+
+bool Vector4::operator==(const Vector4 &p_vec4) const {
+	return x == p_vec4.x && y == p_vec4.y && z == p_vec4.z && w == p_vec4.w;
+}
+
+bool Vector4::operator!=(const Vector4 &p_vec4) const {
+	return x != p_vec4.x || y != p_vec4.y || z != p_vec4.z || w != p_vec4.w;
+}
+
+bool Vector4::operator<(const Vector4 &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w < p_v.w;
+			} else {
+				return z < p_v.z;
+			}
+		} else {
+			return y < p_v.y;
+		}
+	} else {
+		return x < p_v.x;
+	}
+}
+
+bool Vector4::operator>(const Vector4 &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w > p_v.w;
+			} else {
+				return z > p_v.z;
+			}
+		} else {
+			return y > p_v.y;
+		}
+	} else {
+		return x > p_v.x;
+	}
+}
+
+bool Vector4::operator<=(const Vector4 &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w <= p_v.w;
+			} else {
+				return z < p_v.z;
+			}
+		} else {
+			return y < p_v.y;
+		}
+	} else {
+		return x < p_v.x;
+	}
+}
+
+bool Vector4::operator>=(const Vector4 &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w >= p_v.w;
+			} else {
+				return z > p_v.z;
+			}
+		} else {
+			return y > p_v.y;
+		}
+	} else {
+		return x > p_v.x;
+	}
+}
+
+_FORCE_INLINE_ Vector4 operator*(const float p_scalar, const Vector4 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector4 operator*(const double p_scalar, const Vector4 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector4 operator*(const int32_t p_scalar, const Vector4 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector4 operator*(const int64_t p_scalar, const Vector4 &p_vec) {
+	return p_vec * p_scalar;
+}
+
+} // namespace godot
+
+#endif // GODOT_VECTOR3_HPP

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

@@ -0,0 +1,345 @@
+/*************************************************************************/
+/*  vector4i.hpp                                                         */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef GODOT_VECTOR4I_HPP
+#define GODOT_VECTOR4I_HPP
+
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/math.hpp>
+
+namespace godot {
+
+class String;
+class Vector4;
+
+class Vector4i {
+	_FORCE_INLINE_ GDNativeTypePtr _native_ptr() const { return (void *)this; }
+
+	friend class Variant;
+
+public:
+	enum Axis {
+		AXIS_X,
+		AXIS_Y,
+		AXIS_Z,
+		AXIS_W,
+	};
+
+	union {
+		struct {
+			int32_t x;
+			int32_t y;
+			int32_t z;
+			int32_t w;
+		};
+
+		int32_t coord[4] = { 0 };
+	};
+
+	_FORCE_INLINE_ const int32_t &operator[](const int p_axis) const {
+		return coord[p_axis];
+	}
+
+	_FORCE_INLINE_ int32_t &operator[](const int p_axis) {
+		return coord[p_axis];
+	}
+
+	void set_axis(const int p_axis, const int32_t p_value);
+	int32_t get_axis(const int p_axis) const;
+
+	Vector4i::Axis min_axis_index() const;
+	Vector4i::Axis max_axis_index() const;
+
+	_FORCE_INLINE_ int64_t length_squared() const;
+	_FORCE_INLINE_ double length() const;
+
+	_FORCE_INLINE_ void zero();
+
+	_FORCE_INLINE_ Vector4i abs() const;
+	_FORCE_INLINE_ Vector4i sign() const;
+	Vector4i clamp(const Vector4i &p_min, const Vector4i &p_max) const;
+
+	/* Operators */
+
+	_FORCE_INLINE_ Vector4i &operator+=(const Vector4i &p_v);
+	_FORCE_INLINE_ Vector4i operator+(const Vector4i &p_v) const;
+	_FORCE_INLINE_ Vector4i &operator-=(const Vector4i &p_v);
+	_FORCE_INLINE_ Vector4i operator-(const Vector4i &p_v) const;
+	_FORCE_INLINE_ Vector4i &operator*=(const Vector4i &p_v);
+	_FORCE_INLINE_ Vector4i operator*(const Vector4i &p_v) const;
+	_FORCE_INLINE_ Vector4i &operator/=(const Vector4i &p_v);
+	_FORCE_INLINE_ Vector4i operator/(const Vector4i &p_v) const;
+	_FORCE_INLINE_ Vector4i &operator%=(const Vector4i &p_v);
+	_FORCE_INLINE_ Vector4i operator%(const Vector4i &p_v) const;
+
+	_FORCE_INLINE_ Vector4i &operator*=(const int32_t p_scalar);
+	_FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar) const;
+	_FORCE_INLINE_ Vector4i &operator/=(const int32_t p_scalar);
+	_FORCE_INLINE_ Vector4i operator/(const int32_t p_scalar) const;
+	_FORCE_INLINE_ Vector4i &operator%=(const int32_t p_scalar);
+	_FORCE_INLINE_ Vector4i operator%(const int32_t p_scalar) const;
+
+	_FORCE_INLINE_ Vector4i operator-() const;
+
+	_FORCE_INLINE_ bool operator==(const Vector4i &p_v) const;
+	_FORCE_INLINE_ bool operator!=(const Vector4i &p_v) const;
+	_FORCE_INLINE_ bool operator<(const Vector4i &p_v) const;
+	_FORCE_INLINE_ bool operator<=(const Vector4i &p_v) const;
+	_FORCE_INLINE_ bool operator>(const Vector4i &p_v) const;
+	_FORCE_INLINE_ bool operator>=(const Vector4i &p_v) const;
+
+	operator String() const;
+	operator Vector4() const;
+
+	_FORCE_INLINE_ Vector4i() {}
+	Vector4i(const Vector4 &p_vec4);
+	_FORCE_INLINE_ Vector4i(const int32_t p_x, const int32_t p_y, const int32_t p_z, const int32_t p_w) {
+		x = p_x;
+		y = p_y;
+		z = p_z;
+		w = p_w;
+	}
+};
+
+int64_t Vector4i::length_squared() const {
+	return x * (int64_t)x + y * (int64_t)y + z * (int64_t)z + w * (int64_t)w;
+}
+
+double Vector4i::length() const {
+	return Math::sqrt((double)length_squared());
+}
+
+Vector4i Vector4i::abs() const {
+	return Vector4i(ABS(x), ABS(y), ABS(z), ABS(w));
+}
+
+Vector4i Vector4i::sign() const {
+	return Vector4i(SIGN(x), SIGN(y), SIGN(z), SIGN(w));
+}
+
+/* Operators */
+
+Vector4i &Vector4i::operator+=(const Vector4i &p_v) {
+	x += p_v.x;
+	y += p_v.y;
+	z += p_v.z;
+	w += p_v.w;
+	return *this;
+}
+
+Vector4i Vector4i::operator+(const Vector4i &p_v) const {
+	return Vector4i(x + p_v.x, y + p_v.y, z + p_v.z, w + p_v.w);
+}
+
+Vector4i &Vector4i::operator-=(const Vector4i &p_v) {
+	x -= p_v.x;
+	y -= p_v.y;
+	z -= p_v.z;
+	w -= p_v.w;
+	return *this;
+}
+
+Vector4i Vector4i::operator-(const Vector4i &p_v) const {
+	return Vector4i(x - p_v.x, y - p_v.y, z - p_v.z, w - p_v.w);
+}
+
+Vector4i &Vector4i::operator*=(const Vector4i &p_v) {
+	x *= p_v.x;
+	y *= p_v.y;
+	z *= p_v.z;
+	w *= p_v.w;
+	return *this;
+}
+
+Vector4i Vector4i::operator*(const Vector4i &p_v) const {
+	return Vector4i(x * p_v.x, y * p_v.y, z * p_v.z, w * p_v.w);
+}
+
+Vector4i &Vector4i::operator/=(const Vector4i &p_v) {
+	x /= p_v.x;
+	y /= p_v.y;
+	z /= p_v.z;
+	w /= p_v.w;
+	return *this;
+}
+
+Vector4i Vector4i::operator/(const Vector4i &p_v) const {
+	return Vector4i(x / p_v.x, y / p_v.y, z / p_v.z, w / p_v.w);
+}
+
+Vector4i &Vector4i::operator%=(const Vector4i &p_v) {
+	x %= p_v.x;
+	y %= p_v.y;
+	z %= p_v.z;
+	w %= p_v.w;
+	return *this;
+}
+
+Vector4i Vector4i::operator%(const Vector4i &p_v) const {
+	return Vector4i(x % p_v.x, y % p_v.y, z % p_v.z, w % p_v.w);
+}
+
+Vector4i &Vector4i::operator*=(const int32_t p_scalar) {
+	x *= p_scalar;
+	y *= p_scalar;
+	z *= p_scalar;
+	w *= p_scalar;
+	return *this;
+}
+
+Vector4i Vector4i::operator*(const int32_t p_scalar) const {
+	return Vector4i(x * p_scalar, y * p_scalar, z * p_scalar, w * p_scalar);
+}
+
+// Multiplication operators required to workaround issues with LLVM using implicit conversion.
+
+_FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar, const Vector4i &p_vector) {
+	return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector4i operator*(const int64_t p_scalar, const Vector4i &p_vector) {
+	return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector4i operator*(const float p_scalar, const Vector4i &p_vector) {
+	return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector4i operator*(const double p_scalar, const Vector4i &p_vector) {
+	return p_vector * p_scalar;
+}
+
+Vector4i &Vector4i::operator/=(const int32_t p_scalar) {
+	x /= p_scalar;
+	y /= p_scalar;
+	z /= p_scalar;
+	w /= p_scalar;
+	return *this;
+}
+
+Vector4i Vector4i::operator/(const int32_t p_scalar) const {
+	return Vector4i(x / p_scalar, y / p_scalar, z / p_scalar, w / p_scalar);
+}
+
+Vector4i &Vector4i::operator%=(const int32_t p_scalar) {
+	x %= p_scalar;
+	y %= p_scalar;
+	z %= p_scalar;
+	w %= p_scalar;
+	return *this;
+}
+
+Vector4i Vector4i::operator%(const int32_t p_scalar) const {
+	return Vector4i(x % p_scalar, y % p_scalar, z % p_scalar, w % p_scalar);
+}
+
+Vector4i Vector4i::operator-() const {
+	return Vector4i(-x, -y, -z, -w);
+}
+
+bool Vector4i::operator==(const Vector4i &p_v) const {
+	return (x == p_v.x && y == p_v.y && z == p_v.z && w == p_v.w);
+}
+
+bool Vector4i::operator!=(const Vector4i &p_v) const {
+	return (x != p_v.x || y != p_v.y || z != p_v.z || w != p_v.w);
+}
+
+bool Vector4i::operator<(const Vector4i &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w < p_v.w;
+			} else {
+				return z < p_v.z;
+			}
+		} else {
+			return y < p_v.y;
+		}
+	} else {
+		return x < p_v.x;
+	}
+}
+
+bool Vector4i::operator>(const Vector4i &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w > p_v.w;
+			} else {
+				return z > p_v.z;
+			}
+		} else {
+			return y > p_v.y;
+		}
+	} else {
+		return x > p_v.x;
+	}
+}
+
+bool Vector4i::operator<=(const Vector4i &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w <= p_v.w;
+			} else {
+				return z < p_v.z;
+			}
+		} else {
+			return y < p_v.y;
+		}
+	} else {
+		return x < p_v.x;
+	}
+}
+
+bool Vector4i::operator>=(const Vector4i &p_v) const {
+	if (x == p_v.x) {
+		if (y == p_v.y) {
+			if (z == p_v.z) {
+				return w >= p_v.w;
+			} else {
+				return z > p_v.z;
+			}
+		} else {
+			return y > p_v.y;
+		}
+	} else {
+		return x > p_v.x;
+	}
+}
+
+void Vector4i::zero() {
+	x = y = z = w = 0;
+}
+
+} // namespace godot
+
+#endif // GODOT_VECTOR4I_HPP

+ 39 - 0
src/variant/char_string.cpp

@@ -37,6 +37,8 @@
 
 #include <godot_cpp/godot.hpp>
 
+#include <cmath>
+
 namespace godot {
 
 int CharString::length() const {
@@ -186,6 +188,43 @@ void String::parse_utf16(const char16_t *from, int len) {
 	internal::gdn_interface->string_new_with_utf16_chars_and_len(_native_ptr(), from, len);
 }
 
+String String::num_real(double p_num, bool p_trailing) {
+	if (p_num == (double)(int64_t)p_num) {
+		if (p_trailing) {
+			return num_int64((int64_t)p_num) + ".0";
+		} else {
+			return num_int64((int64_t)p_num);
+		}
+	}
+#ifdef REAL_T_IS_DOUBLE
+	int decimals = 14;
+#else
+	int decimals = 6;
+#endif
+	// We want to align the digits to the above sane default, so we only
+	// need to subtract log10 for numbers with a positive power of ten.
+	if (p_num > 10) {
+		decimals -= (int)floor(log10(p_num));
+	}
+	return num(p_num, decimals);
+}
+
+String itos(int64_t p_val) {
+	return String::num_int64(p_val);
+}
+
+String uitos(uint64_t p_val) {
+	return String::num_uint64(p_val);
+}
+
+String rtos(double p_val) {
+	return String::num(p_val);
+}
+
+String rtoss(double p_val) {
+	return String::num_scientific(p_val);
+}
+
 CharString String::utf8() const {
 	int size = internal::gdn_interface->string_to_utf8_chars(_native_ptr(), nullptr, 0);
 	char *cstr = memnew_arr(char, size + 1);

+ 934 - 0
src/variant/projection.cpp

@@ -0,0 +1,934 @@
+/*************************************************************************/
+/*  projection.cpp                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include <godot_cpp/variant/projection.hpp>
+
+#include <godot_cpp/variant/aabb.hpp>
+#include <godot_cpp/variant/plane.hpp>
+#include <godot_cpp/variant/rect2.hpp>
+#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/transform3d.hpp>
+#include <godot_cpp/variant/variant.hpp>
+
+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];
+}
+
+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;
+		}
+	}
+}
+
+void Projection::set_zero() {
+	for (int i = 0; i < 4; i++) {
+		for (int j = 0; j < 4; j++) {
+			matrix[i][j] = 0;
+		}
+	}
+}
+
+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;
+	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);
+}
+Vector4 Projection::xform_inv(const Vector4 &p_vec4) const {
+	return Vector4(
+			matrix[0][0] * p_vec4.x + matrix[0][1] * p_vec4.y + matrix[0][2] * p_vec4.z + matrix[0][3] * p_vec4.w,
+			matrix[1][0] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[1][2] * p_vec4.z + matrix[1][3] * p_vec4.w,
+			matrix[2][0] * p_vec4.x + matrix[2][1] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[2][3] * p_vec4.w,
+			matrix[3][0] * p_vec4.x + matrix[3][1] * p_vec4.y + matrix[3][2] * p_vec4.z + matrix[3][3] * p_vec4.w);
+}
+
+void Projection::adjust_perspective_znear(real_t p_new_znear) {
+	real_t zfar = get_z_far();
+	real_t znear = p_new_znear;
+
+	real_t deltaZ = zfar - znear;
+	matrix[2][2] = -(zfar + znear) / deltaZ;
+	matrix[3][2] = -2 * znear * zfar / deltaZ;
+}
+
+Projection Projection::create_depth_correction(bool p_flip_y) {
+	Projection proj;
+	proj.set_depth_correction(p_flip_y);
+	return proj;
+}
+
+Projection Projection::create_light_atlas_rect(const Rect2 &p_rect) {
+	Projection proj;
+	proj.set_light_atlas_rect(p_rect);
+	return proj;
+}
+
+Projection Projection::create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) {
+	Projection proj;
+	proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov);
+	return proj;
+}
+
+Projection Projection::create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) {
+	Projection proj;
+	proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov, p_eye, p_intraocular_dist, p_convergence_dist);
+	return proj;
+}
+
+Projection Projection::create_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) {
+	Projection proj;
+	proj.set_for_hmd(p_eye, p_aspect, p_intraocular_dist, p_display_width, p_display_to_lens, p_oversample, p_z_near, p_z_far);
+	return proj;
+}
+
+Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
+	Projection proj;
+	proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar);
+	return proj;
+}
+
+Projection Projection::create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) {
+	Projection proj;
+	proj.set_orthogonal(p_size, p_aspect, p_znear, p_zfar, p_flip_fov);
+	return proj;
+}
+
+Projection Projection::create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) {
+	Projection proj;
+	proj.set_frustum(p_left, p_right, p_bottom, p_top, p_near, p_far);
+	return proj;
+}
+
+Projection Projection::create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) {
+	Projection proj;
+	proj.set_frustum(p_size, p_aspect, p_offset, p_near, p_far, p_flip_fov);
+	return proj;
+}
+
+Projection Projection::create_fit_aabb(const AABB &p_aabb) {
+	Projection proj;
+	proj.scale_translate_to_fit(p_aabb);
+	return proj;
+}
+
+Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const {
+	Projection proj = *this;
+	proj.adjust_perspective_znear(p_new_znear);
+	return proj;
+}
+
+Plane Projection::get_projection_plane(Planes p_plane) const {
+	const real_t *matrix = (const real_t *)this->matrix;
+
+	switch (p_plane) {
+		case PLANE_NEAR: {
+			Plane new_plane = Plane(matrix[3] + matrix[2],
+					matrix[7] + matrix[6],
+					matrix[11] + matrix[10],
+					matrix[15] + matrix[14]);
+
+			new_plane.normal = -new_plane.normal;
+			new_plane.normalize();
+			return new_plane;
+		} break;
+		case PLANE_FAR: {
+			Plane new_plane = Plane(matrix[3] - matrix[2],
+					matrix[7] - matrix[6],
+					matrix[11] - matrix[10],
+					matrix[15] - matrix[14]);
+
+			new_plane.normal = -new_plane.normal;
+			new_plane.normalize();
+			return new_plane;
+		} break;
+		case PLANE_LEFT: {
+			Plane new_plane = Plane(matrix[3] + matrix[0],
+					matrix[7] + matrix[4],
+					matrix[11] + matrix[8],
+					matrix[15] + matrix[12]);
+
+			new_plane.normal = -new_plane.normal;
+			new_plane.normalize();
+			return new_plane;
+		} break;
+		case PLANE_TOP: {
+			Plane new_plane = Plane(matrix[3] - matrix[1],
+					matrix[7] - matrix[5],
+					matrix[11] - matrix[9],
+					matrix[15] - matrix[13]);
+
+			new_plane.normal = -new_plane.normal;
+			new_plane.normalize();
+			return new_plane;
+		} break;
+		case PLANE_RIGHT: {
+			Plane new_plane = Plane(matrix[3] - matrix[0],
+					matrix[7] - matrix[4],
+					matrix[11] - matrix[8],
+					matrix[15] - matrix[12]);
+
+			new_plane.normal = -new_plane.normal;
+			new_plane.normalize();
+			return new_plane;
+		} break;
+		case PLANE_BOTTOM: {
+			Plane new_plane = Plane(matrix[3] + matrix[1],
+					matrix[7] + matrix[5],
+					matrix[11] + matrix[9],
+					matrix[15] + matrix[13]);
+
+			new_plane.normal = -new_plane.normal;
+			new_plane.normalize();
+			return new_plane;
+		} break;
+	}
+
+	return Plane();
+}
+
+Projection Projection::flipped_y() const {
+	Projection proj = *this;
+	proj.flip_y();
+	return proj;
+}
+
+Projection Projection ::jitter_offseted(const Vector2 &p_offset) const {
+	Projection proj = *this;
+	proj.add_jitter_offset(p_offset);
+	return proj;
+}
+
+void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) {
+	if (p_flip_fov) {
+		p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect);
+	}
+
+	real_t sine, cotangent, deltaZ;
+	real_t radians = Math::deg2rad(p_fovy_degrees / 2.0);
+
+	deltaZ = p_z_far - p_z_near;
+	sine = Math::sin(radians);
+
+	if ((deltaZ == 0) || (sine == 0) || (p_aspect == 0)) {
+		return;
+	}
+	cotangent = Math::cos(radians) / sine;
+
+	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;
+}
+
+void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) {
+	if (p_flip_fov) {
+		p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect);
+	}
+
+	real_t left, right, modeltranslation, ymax, xmax, frustumshift;
+
+	ymax = p_z_near * tan(Math::deg2rad(p_fovy_degrees / 2.0));
+	xmax = ymax * p_aspect;
+	frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist;
+
+	switch (p_eye) {
+		case 1: { // left eye
+			left = -xmax + frustumshift;
+			right = xmax + frustumshift;
+			modeltranslation = p_intraocular_dist / 2.0;
+		} break;
+		case 2: { // right eye
+			left = -xmax - frustumshift;
+			right = xmax - frustumshift;
+			modeltranslation = -p_intraocular_dist / 2.0;
+		} break;
+		default: { // mono, should give the same result as set_perspective(p_fovy_degrees,p_aspect,p_z_near,p_z_far,p_flip_fov)
+			left = -xmax;
+			right = xmax;
+			modeltranslation = 0.0;
+		} break;
+	}
+
+	set_frustum(left, right, -ymax, ymax, p_z_near, p_z_far);
+
+	// translate matrix by (modeltranslation, 0.0, 0.0)
+	Projection cm;
+	cm.set_identity();
+	cm.matrix[3][0] = modeltranslation;
+	*this = *this * cm;
+}
+
+void Projection::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) {
+	// we first calculate our base frustum on our values without taking our lens magnification into account.
+	real_t f1 = (p_intraocular_dist * 0.5) / p_display_to_lens;
+	real_t f2 = ((p_display_width - p_intraocular_dist) * 0.5) / p_display_to_lens;
+	real_t f3 = (p_display_width / 4.0) / p_display_to_lens;
+
+	// now we apply our oversample factor to increase our FOV. how much we oversample is always a balance we strike between performance and how much
+	// we're willing to sacrifice in FOV.
+	real_t add = ((f1 + f2) * (p_oversample - 1.0)) / 2.0;
+	f1 += add;
+	f2 += add;
+	f3 *= p_oversample;
+
+	// always apply KEEP_WIDTH aspect ratio
+	f3 /= p_aspect;
+
+	switch (p_eye) {
+		case 1: { // left eye
+			set_frustum(-f2 * p_z_near, f1 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far);
+		} break;
+		case 2: { // right eye
+			set_frustum(-f1 * p_z_near, f2 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far);
+		} break;
+		default: { // mono, does not apply here!
+		} break;
+	}
+}
+
+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;
+}
+
+void Projection::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) {
+	if (!p_flip_fov) {
+		p_size *= p_aspect;
+	}
+
+	set_orthogonal(-p_size / 2, +p_size / 2, -p_size / p_aspect / 2, +p_size / p_aspect / 2, p_znear, p_zfar);
+}
+
+void Projection::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) {
+	ERR_FAIL_COND(p_right <= p_left);
+	ERR_FAIL_COND(p_top <= p_bottom);
+	ERR_FAIL_COND(p_far <= p_near);
+
+	real_t *te = &matrix[0][0];
+	real_t x = 2 * p_near / (p_right - p_left);
+	real_t y = 2 * p_near / (p_top - p_bottom);
+
+	real_t a = (p_right + p_left) / (p_right - p_left);
+	real_t b = (p_top + p_bottom) / (p_top - p_bottom);
+	real_t c = -(p_far + p_near) / (p_far - p_near);
+	real_t d = -2 * p_far * p_near / (p_far - p_near);
+
+	te[0] = x;
+	te[1] = 0;
+	te[2] = 0;
+	te[3] = 0;
+	te[4] = 0;
+	te[5] = y;
+	te[6] = 0;
+	te[7] = 0;
+	te[8] = a;
+	te[9] = b;
+	te[10] = c;
+	te[11] = -1;
+	te[12] = 0;
+	te[13] = 0;
+	te[14] = d;
+	te[15] = 0;
+}
+
+void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) {
+	if (!p_flip_fov) {
+		p_size *= p_aspect;
+	}
+
+	set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far);
+}
+
+real_t Projection::get_z_far() const {
+	const real_t *matrix = (const real_t *)this->matrix;
+	Plane new_plane = Plane(matrix[3] - matrix[2],
+			matrix[7] - matrix[6],
+			matrix[11] - matrix[10],
+			matrix[15] - matrix[14]);
+
+	new_plane.normal = -new_plane.normal;
+	new_plane.normalize();
+
+	return new_plane.d;
+}
+
+real_t Projection::get_z_near() const {
+	const real_t *matrix = (const real_t *)this->matrix;
+	Plane new_plane = Plane(matrix[3] + matrix[2],
+			matrix[7] + matrix[6],
+			matrix[11] + matrix[10],
+			-matrix[15] - matrix[14]);
+
+	new_plane.normalize();
+	return new_plane.d;
+}
+
+Vector2 Projection::get_viewport_half_extents() const {
+	const real_t *matrix = (const real_t *)this->matrix;
+	///////--- Near Plane ---///////
+	Plane near_plane = Plane(matrix[3] + matrix[2],
+			matrix[7] + matrix[6],
+			matrix[11] + matrix[10],
+			-matrix[15] - matrix[14]);
+	near_plane.normalize();
+
+	///////--- Right Plane ---///////
+	Plane right_plane = Plane(matrix[3] - matrix[0],
+			matrix[7] - matrix[4],
+			matrix[11] - matrix[8],
+			-matrix[15] + matrix[12]);
+	right_plane.normalize();
+
+	Plane top_plane = Plane(matrix[3] - matrix[1],
+			matrix[7] - matrix[5],
+			matrix[11] - matrix[9],
+			-matrix[15] + matrix[13]);
+	top_plane.normalize();
+
+	Vector3 res;
+	near_plane.intersect_3(right_plane, top_plane, &res);
+
+	return Vector2(res.x, res.y);
+}
+
+Vector2 Projection::get_far_plane_half_extents() const {
+	const real_t *matrix = (const real_t *)this->matrix;
+	///////--- Far Plane ---///////
+	Plane far_plane = Plane(matrix[3] - matrix[2],
+			matrix[7] - matrix[6],
+			matrix[11] - matrix[10],
+			-matrix[15] + matrix[14]);
+	far_plane.normalize();
+
+	///////--- Right Plane ---///////
+	Plane right_plane = Plane(matrix[3] - matrix[0],
+			matrix[7] - matrix[4],
+			matrix[11] - matrix[8],
+			-matrix[15] + matrix[12]);
+	right_plane.normalize();
+
+	Plane top_plane = Plane(matrix[3] - matrix[1],
+			matrix[7] - matrix[5],
+			matrix[11] - matrix[9],
+			-matrix[15] + matrix[13]);
+	top_plane.normalize();
+
+	Vector3 res;
+	far_plane.intersect_3(right_plane, top_plane, &res);
+
+	return Vector2(res.x, res.y);
+}
+
+bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const {
+	Array planes = get_projection_planes(Transform3D());
+	const Planes intersections[8][3] = {
+		{ PLANE_FAR, PLANE_LEFT, PLANE_TOP },
+		{ PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM },
+		{ PLANE_FAR, PLANE_RIGHT, PLANE_TOP },
+		{ PLANE_FAR, PLANE_RIGHT, PLANE_BOTTOM },
+		{ PLANE_NEAR, PLANE_LEFT, PLANE_TOP },
+		{ PLANE_NEAR, PLANE_LEFT, PLANE_BOTTOM },
+		{ PLANE_NEAR, PLANE_RIGHT, PLANE_TOP },
+		{ PLANE_NEAR, PLANE_RIGHT, PLANE_BOTTOM },
+	};
+
+	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);
+		ERR_FAIL_COND_V(!res, false);
+		p_8points[i] = p_transform.xform(point);
+	}
+
+	return true;
+}
+
+Array Projection::get_projection_planes(const Transform3D &p_transform) const {
+	/** Fast Plane Extraction from combined modelview/projection matrices.
+	 * References:
+	 * https://web.archive.org/web/20011221205252/https://www.markmorley.com/opengl/frustumculling.html
+	 * https://web.archive.org/web/20061020020112/https://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf
+	 */
+
+	Array planes;
+
+	const real_t *matrix = (const real_t *)this->matrix;
+
+	Plane new_plane;
+
+	///////--- Near Plane ---///////
+	new_plane = Plane(matrix[3] + matrix[2],
+			matrix[7] + matrix[6],
+			matrix[11] + matrix[10],
+			matrix[15] + matrix[14]);
+
+	new_plane.normal = -new_plane.normal;
+	new_plane.normalize();
+
+	planes.push_back(p_transform.xform(new_plane));
+
+	///////--- Far Plane ---///////
+	new_plane = Plane(matrix[3] - matrix[2],
+			matrix[7] - matrix[6],
+			matrix[11] - matrix[10],
+			matrix[15] - matrix[14]);
+
+	new_plane.normal = -new_plane.normal;
+	new_plane.normalize();
+
+	planes.push_back(p_transform.xform(new_plane));
+
+	///////--- Left Plane ---///////
+	new_plane = Plane(matrix[3] + matrix[0],
+			matrix[7] + matrix[4],
+			matrix[11] + matrix[8],
+			matrix[15] + matrix[12]);
+
+	new_plane.normal = -new_plane.normal;
+	new_plane.normalize();
+
+	planes.push_back(p_transform.xform(new_plane));
+
+	///////--- Top Plane ---///////
+	new_plane = Plane(matrix[3] - matrix[1],
+			matrix[7] - matrix[5],
+			matrix[11] - matrix[9],
+			matrix[15] - matrix[13]);
+
+	new_plane.normal = -new_plane.normal;
+	new_plane.normalize();
+
+	planes.push_back(p_transform.xform(new_plane));
+
+	///////--- Right Plane ---///////
+	new_plane = Plane(matrix[3] - matrix[0],
+			matrix[7] - matrix[4],
+			matrix[11] - matrix[8],
+			matrix[15] - matrix[12]);
+
+	new_plane.normal = -new_plane.normal;
+	new_plane.normalize();
+
+	planes.push_back(p_transform.xform(new_plane));
+
+	///////--- Bottom Plane ---///////
+	new_plane = Plane(matrix[3] + matrix[1],
+			matrix[7] + matrix[5],
+			matrix[11] + matrix[9],
+			matrix[15] + matrix[13]);
+
+	new_plane.normal = -new_plane.normal;
+	new_plane.normalize();
+
+	planes.push_back(p_transform.xform(new_plane));
+
+	return planes;
+}
+
+Projection Projection::inverse() const {
+	Projection cm = *this;
+	cm.invert();
+	return cm;
+}
+
+void Projection::invert() {
+	int i, j, k;
+	int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
+	real_t pvt_val; /* Value of current pivot element */
+	real_t hold; /* Temporary storage */
+	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_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)) {
+					pvt_i[k] = i;
+					pvt_j[k] = j;
+					pvt_val = matrix[i][j];
+				}
+			}
+		}
+
+		/** Product of pivots, gives determinant when finished **/
+		determinant *= pvt_val;
+		if (Math::is_zero_approx(determinant)) {
+			return; /** Matrix is singular (zero determinant). **/
+		}
+
+		/** "Interchange" elements (with sign change stuff) **/
+		i = pvt_i[k];
+		if (i != k) { /** If elements are different **/
+			for (j = 0; j < 4; j++) {
+				hold = -matrix[k][j];
+				matrix[k][j] = matrix[i][j];
+				matrix[i][j] = hold;
+			}
+		}
+
+		/** "Interchange" columns **/
+		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;
+			}
+		}
+
+		/** Divide column by minus pivot value **/
+		for (i = 0; i < 4; i++) {
+			if (i != k) {
+				matrix[i][k] /= (-pvt_val);
+			}
+		}
+
+		/** Reduce the matrix **/
+		for (i = 0; i < 4; i++) {
+			hold = matrix[i][k];
+			for (j = 0; j < 4; j++) {
+				if (i != k && j != k) {
+					matrix[i][j] += hold * matrix[k][j];
+				}
+			}
+		}
+
+		/** Divide row by pivot **/
+		for (j = 0; j < 4; j++) {
+			if (j != k) {
+				matrix[k][j] /= pvt_val;
+			}
+		}
+
+		/** Replace pivot by reciprocal (at last we can touch it). **/
+		matrix[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 */
+			for (j = 0; j < 4; j++) {
+				hold = matrix[k][j];
+				matrix[k][j] = -matrix[i][j];
+				matrix[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;
+			}
+		}
+	}
+}
+
+void Projection::flip_y() {
+	for (int i = 0; i < 4; i++) {
+		matrix[1][i] = -matrix[1][i];
+	}
+}
+
+Projection::Projection() {
+	set_identity();
+}
+
+Projection Projection::operator*(const Projection &p_matrix) const {
+	Projection new_matrix;
+
+	for (int j = 0; j < 4; j++) {
+		for (int i = 0; i < 4; i++) {
+			real_t ab = 0;
+			for (int k = 0; k < 4; k++) {
+				ab += matrix[k][i] * p_matrix.matrix[j][k];
+			}
+			new_matrix.matrix[j][i] = ab;
+		}
+	}
+
+	return new_matrix;
+}
+
+void Projection::set_depth_correction(bool p_flip_y) {
+	real_t *m = &matrix[0][0];
+
+	m[0] = 1;
+	m[1] = 0.0;
+	m[2] = 0.0;
+	m[3] = 0.0;
+	m[4] = 0.0;
+	m[5] = p_flip_y ? -1 : 1;
+	m[6] = 0.0;
+	m[7] = 0.0;
+	m[8] = 0.0;
+	m[9] = 0.0;
+	m[10] = 0.5;
+	m[11] = 0.0;
+	m[12] = 0.0;
+	m[13] = 0.0;
+	m[14] = 0.5;
+	m[15] = 1.0;
+}
+
+void Projection::set_light_bias() {
+	real_t *m = &matrix[0][0];
+
+	m[0] = 0.5;
+	m[1] = 0.0;
+	m[2] = 0.0;
+	m[3] = 0.0;
+	m[4] = 0.0;
+	m[5] = 0.5;
+	m[6] = 0.0;
+	m[7] = 0.0;
+	m[8] = 0.0;
+	m[9] = 0.0;
+	m[10] = 0.5;
+	m[11] = 0.0;
+	m[12] = 0.5;
+	m[13] = 0.5;
+	m[14] = 0.5;
+	m[15] = 1.0;
+}
+
+void Projection::set_light_atlas_rect(const Rect2 &p_rect) {
+	real_t *m = &matrix[0][0];
+
+	m[0] = p_rect.size.width;
+	m[1] = 0.0;
+	m[2] = 0.0;
+	m[3] = 0.0;
+	m[4] = 0.0;
+	m[5] = p_rect.size.height;
+	m[6] = 0.0;
+	m[7] = 0.0;
+	m[8] = 0.0;
+	m[9] = 0.0;
+	m[10] = 1.0;
+	m[11] = 0.0;
+	m[12] = p_rect.position.x;
+	m[13] = p_rect.position.y;
+	m[14] = 0.0;
+	m[15] = 1.0;
+}
+
+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]);
+		}
+	}
+
+	return str;
+}
+
+real_t Projection::get_aspect() const {
+	Vector2 vp_he = get_viewport_half_extents();
+	return vp_he.x / vp_he.y;
+}
+
+int Projection::get_pixels_per_meter(int p_for_pixel_width) const {
+	Vector3 result = xform(Vector3(1, 0, -1));
+
+	return int((result.x * 0.5 + 0.5) * p_for_pixel_width);
+}
+
+bool Projection::is_orthogonal() const {
+	return matrix[3][3] == 1.0;
+}
+
+real_t Projection::get_fov() const {
+	const real_t *matrix = (const real_t *)this->matrix;
+
+	Plane right_plane = Plane(matrix[3] - matrix[0],
+			matrix[7] - matrix[4],
+			matrix[11] - matrix[8],
+			-matrix[15] + matrix[12]);
+	right_plane.normalize();
+
+	if ((matrix[8] == 0) && (matrix[9] == 0)) {
+		return Math::rad2deg(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],
+				matrix[7] + matrix[4],
+				matrix[11] + matrix[8],
+				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)));
+	}
+}
+
+float Projection::get_lod_multiplier() const {
+	if (is_orthogonal()) {
+		return get_viewport_half_extents().x;
+	} else {
+		float zn = get_z_near();
+		float width = get_viewport_half_extents().x * 2.0;
+		return 1.0 / (zn / width);
+	}
+
+	// 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;
+}
+
+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);
+
+	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);
+
+	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);
+
+	matrix[0][3] = 0;
+	matrix[1][3] = 0;
+	matrix[2][3] = 0;
+	matrix[3][3] = 1;
+}
+
+void Projection::add_jitter_offset(const Vector2 &p_offset) {
+	matrix[3][0] += p_offset.x;
+	matrix[3][1] += p_offset.y;
+}
+
+Projection::operator Transform3D() const {
+	Transform3D tr;
+	const real_t *m = &matrix[0][0];
+
+	tr.basis.elements[0][0] = m[0];
+	tr.basis.elements[1][0] = m[1];
+	tr.basis.elements[2][0] = m[2];
+
+	tr.basis.elements[0][1] = m[4];
+	tr.basis.elements[1][1] = m[5];
+	tr.basis.elements[2][1] = m[6];
+
+	tr.basis.elements[0][2] = m[8];
+	tr.basis.elements[1][2] = m[9];
+	tr.basis.elements[2][2] = m[10];
+
+	tr.origin.x = m[12];
+	tr.origin.y = m[13];
+	tr.origin.z = m[14];
+
+	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;
+}
+Projection::Projection(const Transform3D &p_transform) {
+	const Transform3D &tr = p_transform;
+	real_t *m = &matrix[0][0];
+
+	m[0] = tr.basis.elements[0][0];
+	m[1] = tr.basis.elements[1][0];
+	m[2] = tr.basis.elements[2][0];
+	m[3] = 0.0;
+	m[4] = tr.basis.elements[0][1];
+	m[5] = tr.basis.elements[1][1];
+	m[6] = tr.basis.elements[2][1];
+	m[7] = 0.0;
+	m[8] = tr.basis.elements[0][2];
+	m[9] = tr.basis.elements[1][2];
+	m[10] = tr.basis.elements[2][2];
+	m[11] = 0.0;
+	m[12] = tr.origin.x;
+	m[13] = tr.origin.y;
+	m[14] = tr.origin.z;
+	m[15] = 1.0;
+}
+
+Projection::~Projection() {
+}
+
+} // namespace godot

+ 34 - 1
src/variant/variant.cpp

@@ -134,6 +134,14 @@ Variant::Variant(const Transform2D &v) {
 	from_type_constructor[TRANSFORM2D](_native_ptr(), v._native_ptr());
 }
 
+Variant::Variant(const Vector4 &v) {
+	from_type_constructor[VECTOR4](_native_ptr(), v._native_ptr());
+}
+
+Variant::Variant(const Vector4i &v) {
+	from_type_constructor[VECTOR4I](_native_ptr(), v._native_ptr());
+}
+
 Variant::Variant(const Plane &v) {
 	from_type_constructor[PLANE](_native_ptr(), v._native_ptr());
 }
@@ -154,6 +162,10 @@ Variant::Variant(const Transform3D &v) {
 	from_type_constructor[TRANSFORM3D](_native_ptr(), v._native_ptr());
 }
 
+Variant::Variant(const Projection &v) {
+	from_type_constructor[PROJECTION](_native_ptr(), v._native_ptr());
+}
+
 Variant::Variant(const Color &v) {
 	from_type_constructor[COLOR](_native_ptr(), v._native_ptr());
 }
@@ -317,6 +329,18 @@ Variant::operator Transform2D() const {
 	return result;
 }
 
+Variant::operator Vector4() const {
+	Vector4 result;
+	to_type_constructor[VECTOR4](result._native_ptr(), _native_ptr());
+	return result;
+}
+
+Variant::operator Vector4i() const {
+	Vector4i result;
+	to_type_constructor[VECTOR4I](result._native_ptr(), _native_ptr());
+	return result;
+}
+
 Variant::operator Plane() const {
 	Plane result;
 	to_type_constructor[PLANE](result._native_ptr(), _native_ptr());
@@ -347,6 +371,12 @@ Variant::operator Transform3D() const {
 	return result;
 }
 
+Variant::operator Projection() const {
+	Projection result;
+	to_type_constructor[PROJECTION](result._native_ptr(), _native_ptr());
+	return result;
+}
+
 Variant::operator Color() const {
 	Color result;
 	to_type_constructor[COLOR](result._native_ptr(), _native_ptr());
@@ -703,11 +733,14 @@ void Variant::clear() {
 		false, // VECTOR3,
 		false, // VECTOR3I,
 		true, // TRANSFORM2D,
+		false, // VECTOR4,
+		false, // VECTOR4I,
 		false, // PLANE,
 		false, // QUATERNION,
 		true, // AABB,
 		true, // BASIS,
-		true, // TRANSFORM,
+		true, // TRANSFORM3D,
+		true, // PROJECTION,
 
 		// misc types
 		false, // COLOR,

+ 21 - 30
src/variant/vector2.cpp

@@ -30,7 +30,6 @@
 
 #include <godot_cpp/variant/vector2.hpp>
 
-#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/variant/string.hpp>
 #include <godot_cpp/variant/vector2i.hpp>
 
@@ -40,6 +39,10 @@ real_t Vector2::angle() const {
 	return Math::atan2(y, x);
 }
 
+Vector2 Vector2::from_angle(const real_t p_angle) {
+	return Vector2(Math::cos(p_angle), Math::sin(p_angle));
+}
+
 real_t Vector2::length() const {
 	return Math::sqrt(x * x + y * y);
 }
@@ -65,7 +68,7 @@ Vector2 Vector2::normalized() const {
 
 bool Vector2::is_normalized() const {
 	// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
-	return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
+	return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON);
 }
 
 real_t Vector2::distance_to(const Vector2 &p_vector2) const {
@@ -81,7 +84,7 @@ real_t Vector2::angle_to(const Vector2 &p_vector2) const {
 }
 
 real_t Vector2::angle_to_point(const Vector2 &p_vector2) const {
-	return Math::atan2(y - p_vector2.y, x - p_vector2.x);
+	return (p_vector2 - *this).angle();
 }
 
 real_t Vector2::dot(const Vector2 &p_other) const {
@@ -93,7 +96,7 @@ real_t Vector2::cross(const Vector2 &p_other) const {
 }
 
 Vector2 Vector2::sign() const {
-	return Vector2(Math::sign(x), Math::sign(y));
+	return Vector2(SIGN(x), SIGN(y));
 }
 
 Vector2 Vector2::floor() const {
@@ -108,7 +111,7 @@ Vector2 Vector2::round() const {
 	return Vector2(Math::round(x), Math::round(y));
 }
 
-Vector2 Vector2::rotated(real_t p_by) const {
+Vector2 Vector2::rotated(const real_t p_by) const {
 	real_t sine = Math::sin(p_by);
 	real_t cosi = Math::cos(p_by);
 	return Vector2(
@@ -128,14 +131,20 @@ Vector2 Vector2::project(const Vector2 &p_to) const {
 	return p_to * (dot(p_to) / p_to.length_squared());
 }
 
+Vector2 Vector2::clamp(const Vector2 &p_min, const Vector2 &p_max) const {
+	return Vector2(
+			CLAMP(x, p_min.x, p_max.x),
+			CLAMP(y, p_min.y, p_max.y));
+}
+
 Vector2 Vector2::snapped(const Vector2 &p_step) const {
 	return Vector2(
 			Math::snapped(x, p_step.x),
 			Math::snapped(y, p_step.y));
 }
 
-Vector2 Vector2::clamped(real_t p_len) const {
-	real_t l = length();
+Vector2 Vector2::limit_length(const real_t p_len) const {
+	const real_t l = length();
 	Vector2 v = *this;
 	if (l > 0 && p_len < l) {
 		v /= l;
@@ -145,35 +154,17 @@ Vector2 Vector2::clamped(real_t p_len) const {
 	return v;
 }
 
-Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const {
-	Vector2 p0 = p_pre_a;
-	Vector2 p1 = *this;
-	Vector2 p2 = p_b;
-	Vector2 p3 = p_post_b;
-
-	real_t t = p_weight;
-	real_t t2 = t * t;
-	real_t t3 = t2 * t;
-
-	Vector2 out;
-	out = 0.5 * ((p1 * 2.0) +
-						(-p0 + p2) * t +
-						(2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 +
-						(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
-	return out;
-}
-
 Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const {
 	Vector2 v = *this;
 	Vector2 vd = p_to - v;
 	real_t len = vd.length();
-	return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+	return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
 }
 
 // slide returns the component of the vector along the given plane, specified by its normal vector.
 Vector2 Vector2::slide(const Vector2 &p_normal) const {
 #ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector2());
+	ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized.");
 #endif
 	return *this - p_normal * this->dot(p_normal);
 }
@@ -184,9 +175,9 @@ Vector2 Vector2::bounce(const Vector2 &p_normal) const {
 
 Vector2 Vector2::reflect(const Vector2 &p_normal) const {
 #ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector2());
+	ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized.");
 #endif
-	return 2.0 * p_normal * this->dot(p_normal) - *this;
+	return 2.0f * p_normal * this->dot(p_normal) - *this;
 }
 
 bool Vector2::is_equal_approx(const Vector2 &p_v) const {
@@ -194,7 +185,7 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const {
 }
 
 Vector2::operator String() const {
-	return String::num(x, 5) + ", " + String::num(y, 5);
+	return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
 }
 
 Vector2::operator Vector2i() const {

+ 16 - 3
src/variant/vector2i.cpp

@@ -30,12 +30,25 @@
 
 #include <godot_cpp/variant/vector2i.hpp>
 
-#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/variant/string.hpp>
 #include <godot_cpp/variant/vector2.hpp>
 
 namespace godot {
 
+Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const {
+	return Vector2i(
+			CLAMP(x, p_min.x, p_max.x),
+			CLAMP(y, p_min.y, p_max.y));
+}
+
+int64_t Vector2i::length_squared() const {
+	return x * (int64_t)x + y * (int64_t)y;
+}
+
+double Vector2i::length() const {
+	return Math::sqrt((double)length_squared());
+}
+
 Vector2i Vector2i::operator+(const Vector2i &p_v) const {
 	return Vector2i(x + p_v.x, y + p_v.y);
 }
@@ -106,11 +119,11 @@ bool Vector2i::operator!=(const Vector2i &p_vec2) const {
 }
 
 Vector2i::operator String() const {
-	return String::num(x, 0) + ", " + String::num(y, 0);
+	return "(" + itos(x) + ", " + itos(y) + ")";
 }
 
 Vector2i::operator Vector2() const {
-	return Vector2((real_t)x, (real_t)y);
+	return Vector2((int32_t)x, (int32_t)y);
 }
 
 } // namespace godot

+ 54 - 42
src/variant/vector3.cpp

@@ -30,89 +30,101 @@
 
 #include <godot_cpp/variant/vector3.hpp>
 
-#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/variant/basis.hpp>
+#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/vector2.hpp>
 #include <godot_cpp/variant/vector3i.hpp>
 
 namespace godot {
 
-void Vector3::rotate(const Vector3 &p_axis, real_t p_phi) {
-	*this = Basis(p_axis, p_phi).xform(*this);
+void Vector3::rotate(const Vector3 &p_axis, const real_t p_angle) {
+	*this = Basis(p_axis, p_angle).xform(*this);
 }
 
-Vector3 Vector3::rotated(const Vector3 &p_axis, real_t p_phi) const {
+Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_angle) const {
 	Vector3 r = *this;
-	r.rotate(p_axis, p_phi);
+	r.rotate(p_axis, p_angle);
 	return r;
 }
 
-void Vector3::set_axis(int p_axis, real_t p_value) {
+void Vector3::set_axis(const int p_axis, const real_t p_value) {
 	ERR_FAIL_INDEX(p_axis, 3);
 	coord[p_axis] = p_value;
 }
 
-real_t Vector3::get_axis(int p_axis) const {
+real_t Vector3::get_axis(const int p_axis) const {
 	ERR_FAIL_INDEX_V(p_axis, 3, 0);
 	return operator[](p_axis);
 }
 
-int Vector3::min_axis() const {
-	return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2);
+Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const {
+	return Vector3(
+			CLAMP(x, p_min.x, p_max.x),
+			CLAMP(y, p_min.y, p_max.y),
+			CLAMP(z, p_min.z, p_max.z));
 }
 
-int Vector3::max_axis() const {
-	return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
-}
-
-void Vector3::snap(Vector3 p_step) {
+void Vector3::snap(const Vector3 p_step) {
 	x = Math::snapped(x, p_step.x);
 	y = Math::snapped(y, p_step.y);
 	z = Math::snapped(z, p_step.z);
 }
 
-Vector3 Vector3::snapped(Vector3 p_step) const {
+Vector3 Vector3::snapped(const Vector3 p_step) const {
 	Vector3 v = *this;
 	v.snap(p_step);
 	return v;
 }
 
-Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const {
-	Vector3 p0 = p_pre_a;
-	Vector3 p1 = *this;
-	Vector3 p2 = p_b;
-	Vector3 p3 = p_post_b;
-
-	real_t t = p_weight;
-	real_t t2 = t * t;
-	real_t t3 = t2 * t;
-
-	Vector3 out;
-	out = 0.5 * ((p1 * 2.0) +
-						(-p0 + p2) * t +
-						(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 +
-						(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
-	return out;
+Vector3 Vector3::limit_length(const real_t p_len) const {
+	const real_t l = length();
+	Vector3 v = *this;
+	if (l > 0 && p_len < l) {
+		v /= l;
+		v *= p_len;
+	}
+
+	return v;
 }
 
 Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const {
 	Vector3 v = *this;
 	Vector3 vd = p_to - v;
 	real_t len = vd.length();
-	return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+	return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
 }
 
-Basis Vector3::outer(const Vector3 &p_b) const {
-	Vector3 row0(x * p_b.x, x * p_b.y, x * p_b.z);
-	Vector3 row1(y * p_b.x, y * p_b.y, y * p_b.z);
-	Vector3 row2(z * p_b.x, z * p_b.y, z * p_b.z);
+Vector2 Vector3::octahedron_encode() const {
+	Vector3 n = *this;
+	n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z);
+	Vector2 o;
+	if (n.z >= 0.0f) {
+		o.x = n.x;
+		o.y = n.y;
+	} else {
+		o.x = (1.0f - Math::abs(n.y)) * (n.x >= 0.0f ? 1.0f : -1.0f);
+		o.y = (1.0f - Math::abs(n.x)) * (n.y >= 0.0f ? 1.0f : -1.0f);
+	}
+	o.x = o.x * 0.5f + 0.5f;
+	o.y = o.y * 0.5f + 0.5f;
+	return o;
+}
 
-	return Basis(row0, row1, row2);
+Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
+	Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f);
+	Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y));
+	float t = CLAMP(-n.z, 0.0f, 1.0f);
+	n.x += n.x >= 0 ? -t : t;
+	n.y += n.y >= 0 ? -t : t;
+	return n.normalized();
 }
 
-Basis Vector3::to_diagonal_matrix() const {
-	return Basis(x, 0, 0,
-			0, y, 0,
-			0, 0, z);
+Basis Vector3::outer(const Vector3 &p_with) const {
+	Vector3 row0(x * p_with.x, x * p_with.y, x * p_with.z);
+	Vector3 row1(y * p_with.x, y * p_with.y, y * p_with.z);
+	Vector3 row2(z * p_with.x, z * p_with.y, z * p_with.z);
+
+	return Basis(row0, row1, row2);
 }
 
 bool Vector3::is_equal_approx(const Vector3 &p_v) const {
@@ -120,7 +132,7 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const {
 }
 
 Vector3::operator String() const {
-	return (String::num(x, 5) + ", " + String::num(y, 5) + ", " + String::num(z, 5));
+	return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
 }
 
 Vector3::operator Vector3i() const {

+ 15 - 9
src/variant/vector3i.cpp

@@ -30,36 +30,42 @@
 
 #include <godot_cpp/variant/vector3i.hpp>
 
-#include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/variant/string.hpp>
 #include <godot_cpp/variant/vector3.hpp>
 
 namespace godot {
 
-void Vector3i::set_axis(int p_axis, int32_t p_value) {
+void Vector3i::set_axis(const int p_axis, const int32_t p_value) {
 	ERR_FAIL_INDEX(p_axis, 3);
 	coord[p_axis] = p_value;
 }
 
-int32_t Vector3i::get_axis(int p_axis) const {
+int32_t Vector3i::get_axis(const int p_axis) const {
 	ERR_FAIL_INDEX_V(p_axis, 3, 0);
 	return operator[](p_axis);
 }
 
-int Vector3i::min_axis() const {
-	return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2);
+Vector3i::Axis Vector3i::min_axis_index() const {
+	return x < y ? (x < z ? Vector3i::AXIS_X : Vector3i::AXIS_Z) : (y < z ? Vector3i::AXIS_Y : Vector3i::AXIS_Z);
 }
 
-int Vector3i::max_axis() const {
-	return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
+Vector3i::Axis Vector3i::max_axis_index() const {
+	return x < y ? (y < z ? Vector3i::AXIS_Z : Vector3i::AXIS_Y) : (x < z ? Vector3i::AXIS_Z : Vector3i::AXIS_X);
+}
+
+Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const {
+	return Vector3i(
+			CLAMP(x, p_min.x, p_max.x),
+			CLAMP(y, p_min.y, p_max.y),
+			CLAMP(z, p_min.z, p_max.z));
 }
 
 Vector3i::operator String() const {
-	return (String::num(x, 0) + ", " + String::num(y, 0) + ", " + String::num(z, 5));
+	return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")";
 }
 
 Vector3i::operator Vector3() const {
-	return Vector3((real_t)x, (real_t)y, (real_t)z);
+	return Vector3(x, y, z);
 }
 
 } // namespace godot

+ 106 - 0
src/variant/vector4.cpp

@@ -0,0 +1,106 @@
+/*************************************************************************/
+/*  vector4.cpp                                                          */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include <godot_cpp/variant/vector4.hpp>
+
+#include <godot_cpp/variant/basis.hpp>
+#include <godot_cpp/variant/vector4i.hpp>
+
+namespace godot {
+
+bool Vector4::is_equal_approx(const Vector4 &p_vec4) const {
+	return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w);
+}
+
+real_t Vector4::length() const {
+	return Math::sqrt(length_squared());
+}
+
+void Vector4::normalize() {
+	*this /= length();
+}
+
+Vector4 Vector4::normalized() const {
+	return *this / length();
+}
+
+bool Vector4::is_normalized() const {
+	return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // use less epsilon
+}
+
+Vector4 Vector4::abs() const {
+	return Vector4(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w));
+}
+
+Vector4 Vector4::sign() const {
+	return Vector4(Math::sign(x), Math::sign(y), Math::sign(z), Math::sign(w));
+}
+
+Vector4 Vector4::inverse() const {
+	return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
+}
+
+Vector4::Axis Vector4::min_axis_index() const {
+	uint32_t min_index = 0;
+	real_t min_value = x;
+	for (uint32_t i = 1; i < 4; i++) {
+		if (operator[](i) < min_value) {
+			min_index = i;
+			min_value = operator[](i);
+		}
+	}
+	return Vector4::Axis(min_index);
+}
+
+Vector4::Axis Vector4::max_axis_index() const {
+	uint32_t max_index = 0;
+	real_t max_value = x;
+	for (uint32_t i = 1; i < 4; i++) {
+		if (operator[](i) > max_value) {
+			max_index = i;
+			max_value = operator[](i);
+		}
+	}
+	return Vector4::Axis(max_index);
+}
+
+Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
+	return Vector4(
+			CLAMP(x, p_min.x, p_max.x),
+			CLAMP(y, p_min.y, p_max.y),
+			CLAMP(z, p_min.z, p_max.z),
+			CLAMP(w, p_min.w, p_max.w));
+}
+
+Vector4::operator String() const {
+	return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
+}
+
+} // namespace godot

+ 95 - 0
src/variant/vector4i.cpp

@@ -0,0 +1,95 @@
+/*************************************************************************/
+/*  vector4i.cpp                                                         */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include <godot_cpp/variant/vector4i.hpp>
+
+#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/vector4.hpp>
+
+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;
+	for (uint32_t i = 1; i < 4; i++) {
+		if (operator[](i) < min_value) {
+			min_index = i;
+			min_value = operator[](i);
+		}
+	}
+	return Vector4i::Axis(min_index);
+}
+
+Vector4i::Axis Vector4i::max_axis_index() const {
+	uint32_t max_index = 0;
+	int32_t max_value = x;
+	for (uint32_t i = 1; i < 4; i++) {
+		if (operator[](i) > max_value) {
+			max_index = i;
+			max_value = operator[](i);
+		}
+	}
+	return Vector4i::Axis(max_index);
+}
+
+Vector4i Vector4i::clamp(const Vector4i &p_min, const Vector4i &p_max) const {
+	return Vector4i(
+			CLAMP(x, p_min.x, p_max.x),
+			CLAMP(y, p_min.y, p_max.y),
+			CLAMP(z, p_min.z, p_max.z),
+			CLAMP(w, p_min.w, p_max.w));
+}
+
+Vector4i::operator String() const {
+	return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")";
+}
+
+Vector4i::operator Vector4() const {
+	return Vector4(x, y, z, w);
+}
+
+Vector4i::Vector4i(const Vector4 &p_vec4) {
+	x = p_vec4.x;
+	y = p_vec4.y;
+	z = p_vec4.z;
+	w = p_vec4.w;
+}
+
+} // namespace godot

+ 1 - 0
test/demo/main.gd

@@ -19,6 +19,7 @@ func _ready():
 	prints("  returned", $Example.return_something("some string"))
 	prints("  returned const", $Example.return_something_const())
 	prints("  returned ref", $Example.return_extended_ref())
+	prints("  returned ", $Example.get_v4())
 
 	prints("VarArg method calls")
 	var ref = ExampleRef.new()

+ 5 - 0
test/src/example.cpp

@@ -101,6 +101,7 @@ void Example::_bind_methods() {
 	ADD_SUBGROUP("Test subgroup", "group_subgroup_");
 
 	ClassDB::bind_method(D_METHOD("get_custom_position"), &Example::get_custom_position);
+	ClassDB::bind_method(D_METHOD("get_v4"), &Example::get_v4);
 	ClassDB::bind_method(D_METHOD("set_custom_position", "position"), &Example::set_custom_position);
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "group_subgroup_custom_position"), "set_custom_position", "get_custom_position");
 
@@ -205,6 +206,10 @@ Vector2 Example::get_custom_position() const {
 	return custom_position;
 }
 
+Vector4 Example::get_v4() const {
+	return Vector4(1.2, 3.4, 5.6, 7.8);
+}
+
 // Virtual function override.
 bool Example::_has_point(const Vector2 &point) const {
 	Label *label = get_node<Label>("Label");

+ 1 - 0
test/src/example.h

@@ -98,6 +98,7 @@ public:
 	// Property.
 	void set_custom_position(const Vector2 &pos);
 	Vector2 get_custom_position() const;
+	Vector4 get_v4() const;
 
 	// Static method.
 	static int test_static(int p_a, int p_b);

部分文件因文件數量過多而無法顯示