summaryrefslogtreecommitdiff
path: root/core/math
diff options
context:
space:
mode:
Diffstat (limited to 'core/math')
-rw-r--r--core/math/color.h12
-rw-r--r--core/math/quaternion.cpp64
-rw-r--r--core/math/quaternion.h4
-rw-r--r--core/math/transform_2d.cpp40
-rw-r--r--core/math/transform_2d.h9
-rw-r--r--core/math/transform_3d.cpp44
-rw-r--r--core/math/transform_3d.h9
-rw-r--r--core/math/vector3.h11
-rw-r--r--core/math/vector4.cpp116
-rw-r--r--core/math/vector4.h42
-rw-r--r--core/math/vector4i.cpp2
11 files changed, 266 insertions, 87 deletions
diff --git a/core/math/color.h b/core/math/color.h
index 0afa6006a8..65036f74cc 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -215,12 +215,12 @@ struct _NO_DISCARD_ Color {
_FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); }
_FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); }
- _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v()); }
- _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v()); }
- _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v); }
- _FORCE_INLINE_ void set_ok_hsl_h(float p_h) { set_ok_hsl(p_h, get_ok_hsl_s(), get_ok_hsl_l()); }
- _FORCE_INLINE_ void set_ok_hsl_s(float p_s) { set_ok_hsl(get_ok_hsl_h(), p_s, get_ok_hsl_l()); }
- _FORCE_INLINE_ void set_ok_hsl_l(float p_l) { set_ok_hsl(get_ok_hsl_h(), get_ok_hsl_s(), p_l); }
+ _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); }
+ _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); }
+ _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); }
+ _FORCE_INLINE_ void set_ok_hsl_h(float p_h) { set_ok_hsl(p_h, get_ok_hsl_s(), get_ok_hsl_l(), a); }
+ _FORCE_INLINE_ void set_ok_hsl_s(float p_s) { set_ok_hsl(get_ok_hsl_h(), p_s, get_ok_hsl_l(), a); }
+ _FORCE_INLINE_ void set_ok_hsl_l(float p_l) { set_ok_hsl(get_ok_hsl_h(), get_ok_hsl_s(), p_l, a); }
_FORCE_INLINE_ Color() {}
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index 11bfcc1a6f..c681c60694 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -111,7 +111,7 @@ Quaternion Quaternion::log() const {
Quaternion Quaternion::exp() const {
Quaternion src = *this;
Vector3 src_v = Vector3(src.x, src.y, src.z);
- float theta = src_v.length();
+ real_t theta = src_v.length();
if (theta < CMP_EPSILON) {
return Quaternion(0, 0, 0, 1);
}
@@ -132,15 +132,9 @@ Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) con
// adjust signs (if necessary)
if (cosom < 0.0f) {
cosom = -cosom;
- to1.x = -p_to.x;
- to1.y = -p_to.y;
- to1.z = -p_to.z;
- to1.w = -p_to.w;
+ to1 = -p_to;
} else {
- to1.x = p_to.x;
- to1.y = p_to.y;
- to1.z = p_to.z;
- to1.w = p_to.w;
+ to1 = p_to;
}
// calculate coefficients
@@ -189,16 +183,54 @@ Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) c
invFactor * from.w + newFactor * p_to.w);
}
-Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const {
+Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
- //the only way to do slerp :|
- real_t t2 = (1.0f - p_weight) * p_weight * 2;
- Quaternion sp = this->slerp(p_b, p_weight);
- Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight);
- return sp.slerpni(sq, t2);
+ Quaternion from_q = *this;
+ Quaternion pre_q = p_pre_a;
+ Quaternion to_q = p_b;
+ Quaternion post_q = p_post_b;
+
+ // Align flip phases.
+ from_q = Basis(from_q).get_rotation_quaternion();
+ pre_q = Basis(pre_q).get_rotation_quaternion();
+ to_q = Basis(to_q).get_rotation_quaternion();
+ post_q = Basis(post_q).get_rotation_quaternion();
+
+ // Flip quaternions to shortest path if necessary.
+ bool flip1 = signbit(from_q.dot(pre_q));
+ pre_q = flip1 ? -pre_q : pre_q;
+ bool flip2 = signbit(from_q.dot(to_q));
+ to_q = flip2 ? -to_q : to_q;
+ bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q));
+ post_q = flip3 ? -post_q : post_q;
+
+ // Calc by Expmap in from_q space.
+ Quaternion ln_from = Quaternion(0, 0, 0, 0);
+ Quaternion ln_to = (from_q.inverse() * to_q).log();
+ Quaternion ln_pre = (from_q.inverse() * pre_q).log();
+ Quaternion ln_post = (from_q.inverse() * post_q).log();
+ Quaternion ln = Quaternion(0, 0, 0, 0);
+ ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight);
+ ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight);
+ ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight);
+ Quaternion q1 = from_q * ln.exp();
+
+ // Calc by Expmap in to_q space.
+ ln_from = (to_q.inverse() * from_q).log();
+ ln_to = Quaternion(0, 0, 0, 0);
+ ln_pre = (to_q.inverse() * pre_q).log();
+ ln_post = (to_q.inverse() * post_q).log();
+ ln = Quaternion(0, 0, 0, 0);
+ ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight);
+ ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight);
+ ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight);
+ Quaternion q2 = to_q * ln.exp();
+
+ // To cancel error made by Expmap ambiguity, do blends.
+ return q1.slerp(q2, p_weight);
}
Quaternion::operator String() const {
@@ -213,7 +245,7 @@ Vector3 Quaternion::get_axis() const {
return Vector3(x * r, y * r, z * r);
}
-float Quaternion::get_angle() const {
+real_t Quaternion::get_angle() const {
return 2 * Math::acos(w);
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index 9801746659..cb54a6f540 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -71,10 +71,10 @@ struct _NO_DISCARD_ Quaternion {
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
- Quaternion cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
+ Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
Vector3 get_axis() const;
- float get_angle() const;
+ real_t get_angle() const;
_FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
r_angle = 2 * Math::acos(w);
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index cbd2fd3fa1..226076029b 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -136,11 +136,11 @@ void Transform2D::scale_basis(const Size2 &p_scale) {
columns[1][1] *= p_scale.y;
}
-void Transform2D::translate(const real_t p_tx, const real_t p_ty) {
- translate(Vector2(p_tx, p_ty));
+void Transform2D::translate_local(const real_t p_tx, const real_t p_ty) {
+ translate_local(Vector2(p_tx, p_ty));
}
-void Transform2D::translate(const Vector2 &p_translation) {
+void Transform2D::translate_local(const Vector2 &p_translation) {
columns[2] += basis_xform(p_translation);
}
@@ -217,18 +217,24 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
return t;
}
-Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
Transform2D copy = *this;
- copy.scale(p_scale);
+ copy.scale_basis(p_scale);
return copy;
}
-Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+ // Equivalent to left multiplication
Transform2D copy = *this;
- copy.scale_basis(p_scale);
+ copy.scale(p_scale);
return copy;
}
+Transform2D Transform2D::scaled_local(const Size2 &p_scale) const {
+ // Equivalent to right multiplication
+ return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]);
+}
+
Transform2D Transform2D::untranslated() const {
Transform2D copy = *this;
copy.columns[2] = Vector2();
@@ -236,15 +242,23 @@ Transform2D Transform2D::untranslated() const {
}
Transform2D Transform2D::translated(const Vector2 &p_offset) const {
- Transform2D copy = *this;
- copy.translate(p_offset);
- return copy;
+ // Equivalent to left multiplication
+ return Transform2D(columns[0], columns[1], columns[2] + p_offset);
+}
+
+Transform2D Transform2D::translated_local(const Vector2 &p_offset) const {
+ // Equivalent to right multiplication
+ return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset));
}
Transform2D Transform2D::rotated(const real_t p_angle) const {
- Transform2D copy = *this;
- copy.rotate(p_angle);
- return copy;
+ // Equivalent to left multiplication
+ return Transform2D(p_angle, Vector2()) * (*this);
+}
+
+Transform2D Transform2D::rotated_local(const real_t p_angle) const {
+ // Equivalent to right multiplication
+ return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped.
}
real_t Transform2D::basis_determinant() const {
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index 72d34a5d4c..f23f32867a 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -74,8 +74,8 @@ struct _NO_DISCARD_ Transform2D {
void scale(const Size2 &p_scale);
void scale_basis(const Size2 &p_scale);
- void translate(const real_t p_tx, const real_t p_ty);
- void translate(const Vector2 &p_translation);
+ void translate_local(const real_t p_tx, const real_t p_ty);
+ void translate_local(const Vector2 &p_translation);
real_t basis_determinant() const;
@@ -85,10 +85,13 @@ struct _NO_DISCARD_ Transform2D {
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
- Transform2D scaled(const Size2 &p_scale) const;
Transform2D basis_scaled(const Size2 &p_scale) const;
+ Transform2D scaled(const Size2 &p_scale) const;
+ Transform2D scaled_local(const Size2 &p_scale) const;
Transform2D translated(const Vector2 &p_offset) const;
+ Transform2D translated_local(const Vector2 &p_offset) const;
Transform2D rotated(const real_t p_angle) const;
+ Transform2D rotated_local(const real_t p_angle) const;
Transform2D untranslated() const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index 76b31daa76..a634faca9a 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -62,7 +62,15 @@ void Transform3D::rotate(const Vector3 &p_axis, real_t p_angle) {
}
Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_angle) const {
- return Transform3D(Basis(p_axis, p_angle), Vector3()) * (*this);
+ // Equivalent to left multiplication
+ Basis p_basis(p_axis, p_angle);
+ return Transform3D(p_basis * basis, p_basis.xform(origin));
+}
+
+Transform3D Transform3D::rotated_local(const Vector3 &p_axis, real_t p_angle) const {
+ // Equivalent to right multiplication
+ Basis p_basis(p_axis, p_angle);
+ return Transform3D(basis * p_basis, origin);
}
void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) {
@@ -70,17 +78,23 @@ void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) {
}
Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const {
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_V_MSG(origin.is_equal_approx(p_target), Transform3D(), "The transform's origin and target can't be equal.");
+#endif
Transform3D t = *this;
t.basis = Basis::looking_at(p_target - origin, p_up);
return t;
}
void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) {
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_MSG(p_eye.is_equal_approx(p_target), "The eye and target vectors can't be equal.");
+#endif
basis = Basis::looking_at(p_target - p_eye, p_up);
origin = p_eye;
}
-Transform3D Transform3D::sphere_interpolate_with(const Transform3D &p_transform, real_t p_c) const {
+Transform3D Transform3D::spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const {
/* not sure if very "efficient" but good enough? */
Transform3D interp;
@@ -114,29 +128,37 @@ void Transform3D::scale(const Vector3 &p_scale) {
}
Transform3D Transform3D::scaled(const Vector3 &p_scale) const {
- Transform3D t = *this;
- t.scale(p_scale);
- return t;
+ // Equivalent to left multiplication
+ return Transform3D(basis.scaled(p_scale), origin * p_scale);
+}
+
+Transform3D Transform3D::scaled_local(const Vector3 &p_scale) const {
+ // Equivalent to right multiplication
+ return Transform3D(basis.scaled_local(p_scale), origin);
}
void Transform3D::scale_basis(const Vector3 &p_scale) {
basis.scale(p_scale);
}
-void Transform3D::translate(real_t p_tx, real_t p_ty, real_t p_tz) {
- translate(Vector3(p_tx, p_ty, p_tz));
+void Transform3D::translate_local(real_t p_tx, real_t p_ty, real_t p_tz) {
+ translate_local(Vector3(p_tx, p_ty, p_tz));
}
-void Transform3D::translate(const Vector3 &p_translation) {
+void Transform3D::translate_local(const Vector3 &p_translation) {
for (int i = 0; i < 3; i++) {
origin[i] += basis[i].dot(p_translation);
}
}
Transform3D Transform3D::translated(const Vector3 &p_translation) const {
- Transform3D t = *this;
- t.translate(p_translation);
- return t;
+ // Equivalent to left multiplication
+ return Transform3D(basis, origin + p_translation);
+}
+
+Transform3D Transform3D::translated_local(const Vector3 &p_translation) const {
+ // Equivalent to right multiplication
+ return Transform3D(basis, origin + basis.xform(p_translation));
}
void Transform3D::orthonormalize() {
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index 25832434cd..b572e90859 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -46,6 +46,7 @@ struct _NO_DISCARD_ Transform3D {
Transform3D affine_inverse() const;
Transform3D rotated(const Vector3 &p_axis, real_t p_angle) const;
+ Transform3D rotated_local(const Vector3 &p_axis, real_t p_angle) const;
void rotate(const Vector3 &p_axis, real_t p_angle);
void rotate_basis(const Vector3 &p_axis, real_t p_angle);
@@ -55,10 +56,12 @@ struct _NO_DISCARD_ Transform3D {
void scale(const Vector3 &p_scale);
Transform3D scaled(const Vector3 &p_scale) const;
+ Transform3D scaled_local(const Vector3 &p_scale) const;
void scale_basis(const Vector3 &p_scale);
- void translate(real_t p_tx, real_t p_ty, real_t p_tz);
- void translate(const Vector3 &p_translation);
+ void translate_local(real_t p_tx, real_t p_ty, real_t p_tz);
+ void translate_local(const Vector3 &p_translation);
Transform3D translated(const Vector3 &p_translation) const;
+ Transform3D translated_local(const Vector3 &p_translation) const;
const Basis &get_basis() const { return basis; }
void set_basis(const Basis &p_basis) { basis = p_basis; }
@@ -100,7 +103,7 @@ struct _NO_DISCARD_ Transform3D {
void operator*=(const real_t p_val);
Transform3D operator*(const real_t p_val) const;
- Transform3D sphere_interpolate_with(const Transform3D &p_transform, real_t p_c) const;
+ Transform3D spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const;
Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const;
_FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const {
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 970416234d..4ce01da60e 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -217,16 +217,25 @@ Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const {
}
Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const {
+ // This method seems more complicated than it really is, since we write out
+ // the internals of some methods for efficiency (mainly, checking length).
real_t start_length_sq = length_squared();
real_t end_length_sq = p_to.length_squared();
if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) {
// Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
return lerp(p_to, p_weight);
}
+ Vector3 axis = cross(p_to);
+ real_t axis_length_sq = axis.length_squared();
+ if (unlikely(axis_length_sq == 0.0f)) {
+ // Colinear vectors have no rotation axis or angle between them, so the best we can do is lerp.
+ return lerp(p_to, p_weight);
+ }
+ axis /= Math::sqrt(axis_length_sq);
real_t start_length = Math::sqrt(start_length_sq);
real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight);
real_t angle = angle_to(p_to);
- return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length);
+ return rotated(axis, angle * p_weight) * (result_length / start_length);
}
Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const {
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index c2a6f8ead2..4697c311b4 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -33,6 +33,40 @@
#include "core/math/basis.h"
#include "core/string/print_string.h"
+void Vector4::set_axis(const int p_axis, const real_t p_value) {
+ ERR_FAIL_INDEX(p_axis, 4);
+ components[p_axis] = p_value;
+}
+
+real_t Vector4::get_axis(const int p_axis) const {
+ ERR_FAIL_INDEX_V(p_axis, 4, 0);
+ return operator[](p_axis);
+}
+
+Vector4::Axis Vector4::min_axis_index() const {
+ uint32_t min_index = 0;
+ real_t min_value = x;
+ for (uint32_t i = 1; i < 4; i++) {
+ if (operator[](i) <= min_value) {
+ min_index = i;
+ min_value = operator[](i);
+ }
+ }
+ return Vector4::Axis(min_index);
+}
+
+Vector4::Axis Vector4::max_axis_index() const {
+ uint32_t max_index = 0;
+ real_t max_value = x;
+ for (uint32_t i = 1; i < 4; i++) {
+ if (operator[](i) > max_value) {
+ max_index = i;
+ max_value = operator[](i);
+ }
+ }
+ return Vector4::Axis(max_index);
+}
+
bool Vector4::is_equal_approx(const Vector4 &p_vec4) const {
return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w);
}
@@ -50,7 +84,17 @@ Vector4 Vector4::normalized() const {
}
bool Vector4::is_normalized() const {
- return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon
+ return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // Use less epsilon.
+}
+
+real_t Vector4::distance_to(const Vector4 &p_to) const {
+ return (p_to - *this).length();
+}
+
+Vector4 Vector4::direction_to(const Vector4 &p_to) const {
+ Vector4 ret(p_to.x - x, p_to.y - y, p_to.z - z, p_to.w - w);
+ ret.normalize();
+ return ret;
}
Vector4 Vector4::abs() const {
@@ -61,32 +105,58 @@ Vector4 Vector4::sign() const {
return Vector4(SIGN(x), SIGN(y), SIGN(z), SIGN(w));
}
-Vector4 Vector4::inverse() const {
- return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
+Vector4 Vector4::floor() const {
+ return Vector4(Math::floor(x), Math::floor(y), Math::floor(z), Math::floor(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 Vector4::ceil() const {
+ return Vector4(Math::ceil(x), Math::ceil(y), Math::ceil(z), Math::ceil(w));
}
-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::round() const {
+ return Vector4(Math::round(x), Math::round(y), Math::round(z), Math::round(w));
+}
+
+Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const {
+ return Vector4(
+ x + (p_weight * (p_to.x - x)),
+ y + (p_weight * (p_to.y - y)),
+ z + (p_weight * (p_to.z - z)),
+ w + (p_weight * (p_to.w - w)));
+}
+
+Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const {
+ Vector4 res = *this;
+ res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
+ res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
+ res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight);
+ res.w = Math::cubic_interpolate(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight);
+ return res;
+}
+
+Vector4 Vector4::posmod(const real_t p_mod) const {
+ return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod));
+}
+
+Vector4 Vector4::posmodv(const Vector4 &p_modv) const {
+ return Vector4(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z), Math::fposmod(w, p_modv.w));
+}
+
+void Vector4::snap(const Vector4 &p_step) {
+ x = Math::snapped(x, p_step.x);
+ y = Math::snapped(y, p_step.y);
+ z = Math::snapped(z, p_step.z);
+ w = Math::snapped(w, p_step.w);
+}
+
+Vector4 Vector4::snapped(const Vector4 &p_step) const {
+ Vector4 v = *this;
+ v.snap(p_step);
+ return v;
+}
+
+Vector4 Vector4::inverse() const {
+ return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
}
Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
diff --git a/core/math/vector4.h b/core/math/vector4.h
index 645c51db87..373a6a1218 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -54,23 +54,45 @@ struct _NO_DISCARD_ Vector4 {
real_t components[4] = { 0, 0, 0, 0 };
};
- _FORCE_INLINE_ real_t &operator[](int idx) {
- return components[idx];
+ _FORCE_INLINE_ real_t &operator[](const int p_axis) {
+ DEV_ASSERT((unsigned int)p_axis < 4);
+ return components[p_axis];
}
- _FORCE_INLINE_ const real_t &operator[](int idx) const {
- return components[idx];
+ _FORCE_INLINE_ const real_t &operator[](const int p_axis) const {
+ DEV_ASSERT((unsigned int)p_axis < 4);
+ return components[p_axis];
}
+
+ _FORCE_INLINE_ void set_all(const real_t p_value);
+
+ void set_axis(const int p_axis, const real_t p_value);
+ real_t get_axis(const int p_axis) const;
+
+ Vector4::Axis min_axis_index() const;
+ Vector4::Axis max_axis_index() const;
+
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
real_t length() const;
void normalize();
Vector4 normalized() const;
bool is_normalized() const;
+
+ real_t distance_to(const Vector4 &p_to) const;
+ Vector4 direction_to(const Vector4 &p_to) const;
+
Vector4 abs() const;
Vector4 sign() const;
-
- Vector4::Axis min_axis_index() const;
- Vector4::Axis max_axis_index() const;
+ Vector4 floor() const;
+ Vector4 ceil() const;
+ Vector4 round() const;
+ Vector4 lerp(const Vector4 &p_to, const real_t p_weight) const;
+ Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const;
+
+ Vector4 posmod(const real_t p_mod) const;
+ Vector4 posmodv(const Vector4 &p_modv) const;
+ void snap(const Vector4 &p_step);
+ Vector4 snapped(const Vector4 &p_step) const;
Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const;
Vector4 inverse() const;
@@ -123,6 +145,10 @@ struct _NO_DISCARD_ Vector4 {
}
};
+void Vector4::set_all(const real_t p_value) {
+ x = y = z = p_value;
+}
+
real_t Vector4::dot(const Vector4 &p_vec4) const {
return x * p_vec4.x + y * p_vec4.y + z * p_vec4.z + w * p_vec4.w;
}
@@ -186,7 +212,7 @@ Vector4 Vector4::operator/(const Vector4 &p_vec4) const {
}
Vector4 Vector4::operator-() const {
- return Vector4(x, y, z, w);
+ return Vector4(-x, -y, -z, -w);
}
Vector4 Vector4::operator*(const real_t &s) const {
diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp
index 8c571b02e3..2dc5b74202 100644
--- a/core/math/vector4i.cpp
+++ b/core/math/vector4i.cpp
@@ -47,7 +47,7 @@ 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) {
+ if (operator[](i) <= min_value) {
min_index = i;
min_value = operator[](i);
}