#![macro_use]
macro_rules! impl_vector_unary_operator {
(
// Name of the vector type.
$Vector:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($components:ident),*),
$Operator:ident,
$func:ident
) => {
impl std::ops::$Operator for $Vector {
type Output = Self;
fn $func(mut self) -> Self::Output {
$(
self.$components = self.$components.$func();
)*
self
}
}
}
}
macro_rules! impl_vector_vector_binary_operator {
(
// Name of the vector type.
$Vector:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($components:ident),*),
$Operator:ident,
$func:ident
) => {
impl std::ops::$Operator for $Vector {
type Output = Self;
fn $func(mut self, rhs: $Vector) -> Self::Output {
$(
self.$components = self.$components.$func(rhs.$components);
)*
self
}
}
}
}
macro_rules! impl_vector_scalar_binary_operator {
(
// Name of the vector type.
$Vector:ty,
// Type of each individual component, for example `i32`.
$Scalar:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($components:ident),*),
$Operator:ident,
$func:ident
) => {
impl std::ops::$Operator<$Scalar> for $Vector {
type Output = Self;
fn $func(mut self, rhs: $Scalar) -> Self::Output {
$(
self.$components = self.$components.$func(rhs);
)*
self
}
}
}
}
macro_rules! impl_scalar_vector_binary_operator {
(
// Name of the vector type.
$Vector:ty,
// Type of each individual component, for example `i32`.
$Scalar:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($components:ident),*),
$Operator:ident,
$func:ident
) => {
impl std::ops::$Operator<$Vector> for $Scalar {
type Output = $Vector;
fn $func(self, mut rhs: $Vector) -> Self::Output {
$(
rhs.$components = rhs.$components.$func(self);
)*
rhs
}
}
}
}
macro_rules! impl_vector_vector_assign_operator {
(
// Name of the vector type.
$Vector:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($components:ident),*),
$Operator:ident,
$func:ident
) => {
impl std::ops::$Operator for $Vector {
fn $func(&mut self, rhs: $Vector) {
$(
self.$components.$func(rhs.$components);
)*
}
}
}
}
macro_rules! impl_vector_scalar_assign_operator {
(
// Name of the vector type.
$Vector:ty,
// Type of each individual component, for example `i32`.
$Scalar:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($components:ident),*),
$Operator:ident,
$func:ident
) => {
impl std::ops::$Operator<$Scalar> for $Vector {
fn $func(&mut self, rhs: $Scalar) {
$(
self.$components.$func(rhs);
)*
}
}
}
}
macro_rules! impl_iter_vector_reduction {
(
// Name of the vector type.
$Vector:ty,
// Name of the reduction trait: `Sum` or `Product`.
$Operator:ident,
// Name of the function on the operator trait, for example `add`.
$func:ident
) => {
impl std::iter::$Operator<Self> for $Vector {
#[doc = concat!("Element-wise ", stringify!($func), " of all vectors in the iterator.")]
fn $func<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
Self::from_glam(iter.map(Self::to_glam).$func())
}
}
impl<'a> std::iter::$Operator<&'a Self> for $Vector {
#[doc = concat!("Element-wise ", stringify!($func), " of all vectors in the iterator.")]
fn $func<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
Self::from_glam(iter.map(|x| Self::to_glam(*x)).$func())
}
}
};
}
macro_rules! impl_vector_operators {
(
// Name of the vector type to be implemented, for example `Vector2`.
$Vector:ty,
// Type of each individual component, for example `real`.
$Scalar:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($components:ident),*)
) => {
impl_vector_unary_operator!($Vector, ($($components),*), Neg, neg);
impl_vector_vector_binary_operator!($Vector, ($($components),*), Add, add);
impl_vector_vector_binary_operator!($Vector, ($($components),*), Sub, sub);
impl_vector_vector_binary_operator!($Vector, ($($components),*), Mul, mul);
impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul);
impl_scalar_vector_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul);
impl_vector_vector_binary_operator!($Vector, ($($components),*), Div, div);
impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Div, div);
impl_iter_vector_reduction!($Vector, Sum, sum);
impl_iter_vector_reduction!($Vector, Product, product);
impl_vector_vector_assign_operator!($Vector, ($($components),*), AddAssign, add_assign);
impl_vector_vector_assign_operator!($Vector, ($($components),*), SubAssign, sub_assign);
impl_vector_vector_assign_operator!($Vector, ($($components),*), MulAssign, mul_assign);
impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), MulAssign, mul_assign);
impl_vector_vector_assign_operator!($Vector, ($($components),*), DivAssign, div_assign);
impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), DivAssign, div_assign);
}
}
macro_rules! impl_vector_index {
(
// Name of the vector type to be implemented, for example `Vector2`.
$Vector:ty,
// Type of each individual component, for example `real`.
$Scalar:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($( $components:ident ),*),
$AxisEnum:ty,
($( $axis_variants:ident ),*)
) => {
impl std::ops::Index<$AxisEnum> for $Vector {
type Output = $Scalar;
fn index(&self, axis: $AxisEnum) -> &$Scalar {
match axis {
$(<$AxisEnum>::$axis_variants => &self.$components),*
}
}
}
impl std::ops::IndexMut<$AxisEnum> for $Vector {
fn index_mut(&mut self, axis: $AxisEnum) -> &mut $Scalar {
match axis {
$(<$AxisEnum>::$axis_variants => &mut self.$components),*
}
}
}
}
}
macro_rules! impl_vector_consts {
(
// Type of target component, for example `real`.
$Scalar:ty
) => {
pub const ZERO: Self = Self::splat(0 as $Scalar);
pub const ONE: Self = Self::splat(1 as $Scalar);
};
}
macro_rules! impl_float_vector_consts {
() => {
pub const INF: Self = Self::splat(real::INFINITY);
};
}
macro_rules! impl_integer_vector_consts {
() => {
pub const MIN: Self = Self::splat(i32::MIN);
pub const MAX: Self = Self::splat(i32::MAX);
};
}
macro_rules! impl_vector2x_consts {
(
// Type of target component, for example `real`.
$Scalar:ty
) => {
pub const LEFT: Self = Self::new(-1 as $Scalar, 0 as $Scalar);
pub const RIGHT: Self = Self::new(1 as $Scalar, 0 as $Scalar);
pub const UP: Self = Self::new(0 as $Scalar, -1 as $Scalar);
pub const DOWN: Self = Self::new(0 as $Scalar, 1 as $Scalar);
};
}
macro_rules! impl_vector3x_consts {
(
// Type of target component, for example `real`.
$Scalar:ty
) => {
pub const LEFT: Self = Self::new(-1 as $Scalar, 0 as $Scalar, 0 as $Scalar);
pub const RIGHT: Self = Self::new(1 as $Scalar, 0 as $Scalar, 0 as $Scalar);
pub const UP: Self = Self::new(0 as $Scalar, 1 as $Scalar, 0 as $Scalar);
pub const DOWN: Self = Self::new(0 as $Scalar, -1 as $Scalar, 0 as $Scalar);
pub const FORWARD: Self = Self::new(0 as $Scalar, 0 as $Scalar, -1 as $Scalar);
pub const BACK: Self = Self::new(0 as $Scalar, 0 as $Scalar, 1 as $Scalar);
};
}
macro_rules! shared_vector_docs {
() => {
"Conversions are provided via various `from_*` and `to_*` functions, not via the `From` trait. This encourages `new()` as the main \
way to construct vectors, is explicit about the conversion taking place, needs no type inference, and works in `const` contexts."
};
}
macro_rules! tuple_type {
($Scalar:ty; $x:ident, $y:ident) => {
($Scalar, $Scalar)
};
($Scalar:ty; $x:ident, $y:ident, $z:ident) => {
($Scalar, $Scalar, $Scalar)
};
($Scalar:ty; $x:ident, $y:ident, $z:ident, $w:ident) => {
($Scalar, $Scalar, $Scalar, $Scalar)
};
}
macro_rules! array_type {
($Scalar:ty; $x:ident, $y:ident) => {
[$Scalar; 2]
};
($Scalar:ty; $x:ident, $y:ident, $z:ident) => {
[$Scalar; 3]
};
($Scalar:ty; $x:ident, $y:ident, $z:ident, $w:ident) => {
[$Scalar; 4]
};
}
macro_rules! impl_vector_fns {
(
// Name of the vector type.
$Vector:ty,
// Name of the glam vector type.
$GlamVector:ty,
// Type of target component, for example `real`.
$Scalar:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($comp:ident),*)
) => {
impl $Vector {
#[inline]
pub const fn new($($comp: $Scalar),*) -> Self {
Self {
$( $comp ),*
}
}
#[inline]
pub const fn splat(v: $Scalar) -> Self {
Self {
$( $comp: v ),*
}
}
#[inline]
pub const fn from_tuple(tuple: tuple_type!($Scalar; $($comp),*)) -> Self {
let ( $($comp,)* ) = tuple;
Self::new( $($comp),* )
}
#[inline]
pub const fn from_array(array: array_type!($Scalar; $($comp),*)) -> Self {
let [ $($comp,)* ] = array;
Self::new( $($comp),* )
}
#[inline]
pub const fn to_tuple(&self) -> tuple_type!($Scalar; $($comp),*) {
( $(self.$comp,)* )
}
#[inline]
pub const fn to_array(&self) -> array_type!($Scalar; $($comp),*) {
[ $(self.$comp,)* ]
}
pub(crate) fn from_glam(v: $GlamVector) -> Self {
Self::new(
$( v.$comp ),*
)
}
pub(crate) fn to_glam(self) -> $GlamVector {
<$GlamVector>::new(
$( self.$comp ),*
)
}
#[inline]
pub fn abs(self) -> Self {
Self::from_glam(self.to_glam().abs())
}
#[inline]
pub fn clamp(self, min: Self, max: Self) -> Self {
Self::from_glam(self.to_glam().clamp(min.to_glam(), max.to_glam()))
}
#[inline]
pub fn length(self) -> real {
(self.length_squared() as real).sqrt()
}
#[inline]
pub fn length_squared(self) -> $Scalar {
self.to_glam().length_squared()
}
#[doc = concat!("You may consider using the fully-qualified syntax `", stringify!($Vector), "::coord_min(a, b)` for symmetry.")]
#[inline]
pub fn coord_min(self, other: Self) -> Self {
self.glam2(&other, |a, b| a.min(b))
}
#[doc = concat!("You may consider using the fully-qualified syntax `", stringify!($Vector), "::coord_max(a, b)` for symmetry.")]
#[inline]
pub fn coord_max(self, other: Self) -> Self {
self.glam2(&other, |a, b| a.max(b))
}
#[inline]
pub fn sign(self) -> Self {
#[inline]
fn f(c: $Scalar) -> $Scalar {
let r = c.partial_cmp(&(0 as $Scalar)).unwrap_or_else(|| panic!("Vector component {c} isn't signed!"));
match r {
Ordering::Equal => 0 as $Scalar,
Ordering::Greater => 1 as $Scalar,
Ordering::Less => -1 as $Scalar,
}
}
Self::new(
$( f(self.$comp) ),*
)
}
}
}
}
pub(super) fn snap_one(mut value: i32, step: i32) -> i32 {
assert!(
value != i32::MIN || step != -1,
"snapped() called on vector component i32::MIN with step component -1"
);
if step != 0 {
let a = (step / 2).checked_add(value).expect(
"snapped() overflowed, this happened because step / 2 + component is not in range of i32",
);
let mut d = a / step;
let r = a % step;
if (r > 0 && step < 0) || (r < 0 && step > 0) {
d -= 1;
}
value = step * d;
}
value
}
macro_rules! inline_impl_integer_vector_fns {
(
// Name of the float-equivalent vector type.
$VectorFloat:ty,
// Names of the components, for example `x, y`.
$($comp:ident),*
) => {
#[inline]
pub fn distance_to(self, to: Self) -> real {
(to - self).length()
}
#[inline]
pub fn distance_squared_to(self, to: Self) -> i32 {
(to - self).length_squared() as i32
}
#[inline]
pub fn clampi(self, min: i32, max: i32) -> Self {
Self::new(
$(
self.$comp.clamp(min, max)
),*
)
}
#[inline]
pub fn mini(self, with: i32) -> Self {
Self::new(
$(
self.$comp.min(with)
),*
)
}
#[inline]
pub fn maxi(self, with: i32) -> Self {
Self::new(
$(
self.$comp.max(with)
),*
)
}
#[inline]
pub fn snapped(self, step: Self) -> Self {
use crate::builtin::vectors::vector_macros::snap_one;
Self::new(
$(
snap_one(self.$comp, step.$comp)
),*
)
}
#[inline]
pub fn snappedi(self, step: i32) -> Self {
self.snapped(Self::splat(step))
}
#[inline]
pub const fn cast_float(self) -> $VectorFloat {
<$VectorFloat>::new( $(self.$comp as real),* )
}
};
}
macro_rules! impl_float_vector_fns {
(
// Name of the vector type.
$Vector:ty,
// Name of the integer-equivalent vector type.
$VectorInt:ty,
// Names of the components, with parentheses, for example `(x, y)`.
($($comp:ident),*)
) => {
impl $Vector {
pub const fn cast_int(self) -> $VectorInt {
<$VectorInt>::new( $(self.$comp as i32),* )
}
#[inline]
pub fn floor(self) -> Self {
Self::from_glam(self.to_glam().floor())
}
#[inline]
pub fn ceil(self) -> Self {
Self::from_glam(self.to_glam().ceil())
}
#[inline]
pub fn cubic_interpolate(self, b: Self, pre_a: Self, post_b: Self, weight: real) -> Self {
Self::new(
$(
self.$comp.cubic_interpolate(b.$comp, pre_a.$comp, post_b.$comp, weight)
),*
)
}
#[inline]
#[allow(clippy::too_many_arguments)]
pub fn cubic_interpolate_in_time(
self,
b: Self,
pre_a: Self,
post_b: Self,
weight: real,
b_t: real,
pre_a_t: real,
post_b_t: real,
) -> Self {
Self::new(
$(
self.$comp.cubic_interpolate_in_time(
b.$comp, pre_a.$comp, post_b.$comp, weight, b_t, pre_a_t, post_b_t,
)
),*
)
}
#[inline]
pub fn try_direction_to(self, to: Self) -> Option<Self> {
(to - self).try_normalized()
}
#[inline]
pub fn direction_to(self, to: Self) -> Self {
self.try_direction_to(to).expect("direction_to() called on equal vectors")
}
#[inline]
pub fn distance_squared_to(self, to: Self) -> real {
(to - self).length_squared()
}
#[inline]
pub fn distance_to(self, to: Self) -> real {
(to - self).length()
}
#[inline]
pub fn dot(self, with: Self) -> real {
self.to_glam().dot(with.to_glam())
}
#[inline]
pub fn is_finite(self) -> bool {
self.to_glam().is_finite()
}
#[inline]
pub fn is_normalized(self) -> bool {
self.to_glam().is_normalized()
}
#[inline]
pub fn is_zero_approx(self) -> bool {
$( self.$comp.is_zero_approx() )&&*
}
#[inline]
pub fn lerp(self, other: Self, weight: real) -> Self {
Self::new(
$( self.$comp.lerp(other.$comp, weight) ),*
)
}
#[inline]
pub fn try_normalized(self) -> Option<Self> {
if self == Self::ZERO {
return None;
}
Some(self / self.length())
}
#[inline]
pub fn normalized(self) -> Self {
self.try_normalized().expect("normalized() called on zero vector")
}
#[inline]
pub fn normalized_or_zero(self) -> Self {
self.try_normalized().unwrap_or_default()
}
#[inline]
pub fn posmod(self, pmod: real) -> Self {
Self::new(
$( self.$comp.fposmod(pmod) ),*
)
}
#[inline]
pub fn posmodv(self, modv: Self) -> Self {
Self::new(
$( self.$comp.fposmod(modv.$comp) ),*
)
}
#[inline]
pub fn round(self) -> Self {
Self::from_glam(self.to_glam().round())
}
#[inline]
pub fn snapped(self, step: Self) -> Self {
Self::new(
$(
self.$comp.snapped(step.$comp)
),*
)
}
}
impl $crate::builtin::math::ApproxEq for $Vector {
#[inline]
#[doc(alias = "is_equal_approx")]
fn approx_eq(&self, other: &Self) -> bool {
$( self.$comp.approx_eq(&other.$comp) )&&*
}
}
};
}
macro_rules! impl_vector2x_fns {
(
// Name of the vector type.
$Vector:ty,
// Name of the 3D-equivalent vector type.
$Vector3D:ty,
// Type of target component, for example `real`.
$Scalar:ty
) => {
impl $Vector {
#[inline]
pub fn aspect(self) -> real {
self.x as real / self.y as real
}
#[doc = concat!("*Godot equivalent: `", stringify!($Vector), ".max_axis_index`*")]
#[inline]
#[doc(alias = "max_axis_index")]
pub fn max_axis(self) -> Option<Vector2Axis> {
match self.x.partial_cmp(&self.y) {
Some(Ordering::Less) => Some(Vector2Axis::Y),
Some(Ordering::Equal) => None,
Some(Ordering::Greater) => Some(Vector2Axis::X),
_ => None,
}
}
#[doc = concat!("*Godot equivalent: `", stringify!($Vector), ".min_axis_index`*")]
#[inline]
#[doc(alias = "min_axis_index")]
pub fn min_axis(self) -> Option<Vector2Axis> {
match self.x.partial_cmp(&self.y) {
Some(Ordering::Less) => Some(Vector2Axis::X),
Some(Ordering::Equal) => None,
Some(Ordering::Greater) => Some(Vector2Axis::Y),
_ => None,
}
}
}
impl $crate::builtin::SwizzleToVector for ($Scalar, $Scalar) {
type Output = $Vector;
fn swizzle_to_vector(self) -> $Vector {
<$Vector>::new(self.0, self.1)
}
}
};
}
macro_rules! impl_vector3x_fns {
(
// Name of the vector type.
$Vector:ty,
// Name of the vector type.
$Vector2D:ty,
// Type of target component, for example `real`.
$Scalar:ty
) => {
impl $Vector {
#[inline]
#[doc(alias = "max_axis_index")]
pub fn max_axis(self) -> Option<Vector3Axis> {
match self.x.partial_cmp(&self.y) {
Some(Ordering::Less) => match self.y.partial_cmp(&self.z) {
Some(Ordering::Less) => Some(Vector3Axis::Z),
Some(Ordering::Equal) => None,
Some(Ordering::Greater) => Some(Vector3Axis::Y),
_ => None,
},
Some(Ordering::Equal) => match self.x.partial_cmp(&self.z) {
Some(Ordering::Less) => Some(Vector3Axis::Z),
_ => None,
},
Some(Ordering::Greater) => match self.x.partial_cmp(&self.z) {
Some(Ordering::Less) => Some(Vector3Axis::Z),
Some(Ordering::Equal) => None,
Some(Ordering::Greater) => Some(Vector3Axis::X),
_ => None,
},
_ => None,
}
}
#[inline]
#[doc(alias = "min_axis_index")]
pub fn min_axis(self) -> Option<Vector3Axis> {
match self.x.partial_cmp(&self.y) {
Some(Ordering::Less) => match self.x.partial_cmp(&self.z) {
Some(Ordering::Less) => Some(Vector3Axis::X),
Some(Ordering::Equal) => None,
Some(Ordering::Greater) => Some(Vector3Axis::Z),
_ => None,
},
Some(Ordering::Equal) => match self.x.partial_cmp(&self.z) {
Some(Ordering::Greater) => Some(Vector3Axis::Z),
_ => None,
},
Some(Ordering::Greater) => match self.y.partial_cmp(&self.z) {
Some(Ordering::Less) => Some(Vector3Axis::Y),
Some(Ordering::Equal) => None,
Some(Ordering::Greater) => Some(Vector3Axis::Z),
_ => None,
},
_ => None,
}
}
}
impl $crate::builtin::SwizzleToVector for ($Scalar, $Scalar, $Scalar) {
type Output = $Vector;
fn swizzle_to_vector(self) -> $Vector {
<$Vector>::new(self.0, self.1, self.2)
}
}
};
}
macro_rules! impl_vector4x_fns {
(
// Name of the vector type.
$Vector:ty,
// Type of target component, for example `real`.
$Scalar:ty
) => {
impl $Vector {
#[inline]
#[doc(alias = "max_axis_index")]
pub fn max_axis(self) -> Option<Vector4Axis> {
let mut max_axis = Vector4Axis::X;
let mut previous = None;
let mut max_value = self.x;
let components = [
(Vector4Axis::Y, self.y),
(Vector4Axis::Z, self.z),
(Vector4Axis::W, self.w),
];
for (axis, value) in components {
if value >= max_value {
max_axis = axis;
previous = Some(max_value);
max_value = value;
}
}
(Some(max_value) != previous).then_some(max_axis)
}
#[inline]
#[doc(alias = "min_axis_index")]
pub fn min_axis(self) -> Option<Vector4Axis> {
let mut min_axis = Vector4Axis::X;
let mut previous = None;
let mut min_value = self.x;
let components = [
(Vector4Axis::Y, self.y),
(Vector4Axis::Z, self.z),
(Vector4Axis::W, self.w),
];
for (axis, value) in components {
if value <= min_value {
min_axis = axis;
previous = Some(min_value);
min_value = value;
}
}
(Some(min_value) != previous).then_some(min_axis)
}
}
impl $crate::builtin::SwizzleToVector for ($Scalar, $Scalar, $Scalar, $Scalar) {
type Output = $Vector;
fn swizzle_to_vector(self) -> $Vector {
<$Vector>::new(self.0, self.1, self.2, self.3)
}
}
};
}
macro_rules! impl_vector2_vector3_fns {
(
// Name of the vector type.
$Vector:ty,
// Names of the components, with parentheses, for example `(x, y, z, w)`.
($($comp:ident),*)
) => {
impl $Vector {
#[inline]
pub fn bezier_derivative(self, control_1: Self, control_2: Self, end: Self, t: real) -> Self {
Self::new(
$(
self.$comp.bezier_derivative(control_1.$comp, control_2.$comp, end.$comp, t)
),*
)
}
#[inline]
pub fn bezier_interpolate(self, control_1: Self, control_2: Self, end: Self, t: real) -> Self {
Self::new(
$(
self.$comp.bezier_interpolate(control_1.$comp, control_2.$comp, end.$comp, t)
),*
)
}
#[inline]
pub fn bounce(self, n: Self) -> Self {
assert!(n.is_normalized(), "n is not normalized!");
-self.reflect(n)
}
#[inline]
pub fn limit_length(self, length: Option<real>) -> Self {
let length = length.unwrap_or(1.0);
Self::from_glam(self.to_glam().clamp_length_max(length))
}
#[inline]
pub fn move_toward(self, to: Self, delta: real) -> Self {
Self::from_glam(self.to_glam().move_towards(to.to_glam(), delta))
}
#[inline]
pub fn project(self, b: Self) -> Self {
Self::from_glam(self.to_glam().project_onto(b.to_glam()))
}
#[inline]
pub fn reflect(self, n: Self) -> Self {
assert!(n.is_normalized(), "n is not normalized!");
2.0 * n * self.dot(n) - self
}
#[inline]
pub fn slide(self, n: Self) -> Self {
assert!(n.is_normalized(), "n is not normalized!");
self - n * self.dot(n)
}
}
};
}
macro_rules! impl_vector3_vector4_fns {
(
// Name of the vector type.
$Vector:ty,
// Names of the components, with parentheses, for example `(x, y, z, w)`.
($($comp:ident),*)
) => {
impl $Vector {
#[inline]
#[doc(alias = "inverse")]
pub fn recip(self) -> Self {
Self::from_glam(self.to_glam().recip())
}
}
};
}