use core::iter::Sum;
use core::ops::Mul;
use crate::scalar::SignedScalar;
use crate::{
bindings::prelude::*, scalar::FloatScalar, Point2, Point3, Point4, Scalar, Size2, Size3, Unit,
};
use crate::{Angle, AsRaw, FromRaw, ToRaw};
pub trait Swizzle<T: Unit> {
#[doc = "Select two components from this vector and return a 2D vector made from"]
#[doc = "those components."]
#[must_use]
fn swizzle2<const X: usize, const Y: usize>(&self) -> Vector2<T>;
#[doc = "Select three components from this vector and return a 3D vector made from"]
#[doc = "those components."]
#[must_use]
fn swizzle3<const X: usize, const Y: usize, const Z: usize>(&self) -> Vector3<T>;
#[doc = "Select four components from this vector and return a 4D vector made from"]
#[doc = "those components."]
#[must_use]
fn swizzle4<const X: usize, const Y: usize, const Z: usize, const W: usize>(
&self,
) -> Vector4<T>;
}
#[repr(C)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = ""))]
pub struct Vector2<T: Unit = f32> {
pub x: T::Scalar,
pub y: T::Scalar,
}
unsafe impl<T: Unit> bytemuck::Zeroable for Vector2<T> {}
unsafe impl<T: Unit> bytemuck::Pod for Vector2<T> {}
#[repr(C)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = ""))]
pub struct Vector3<T: Unit = f32> {
pub x: T::Scalar,
pub y: T::Scalar,
pub z: T::Scalar,
}
unsafe impl<T: Unit> bytemuck::Zeroable for Vector3<T> {}
unsafe impl<T: Unit> bytemuck::Pod for Vector3<T> {}
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = ""))]
#[cfg_attr(
any(
not(any(feature = "scalar-math", target_arch = "spirv")),
feature = "cuda"
),
repr(C, align(16))
)]
pub struct Vector4<T: Unit = f32> {
pub x: T::Scalar,
pub y: T::Scalar,
pub z: T::Scalar,
pub w: T::Scalar,
}
unsafe impl<T: Unit> bytemuck::Zeroable for Vector4<T> {}
unsafe impl<T: Unit> bytemuck::Pod for Vector4<T> {}
macro_rules! vector_interface {
($point_ty:ident $(, $size_ty:ident)?) => {
#[doc = "Instantiate from point."]
#[inline]
#[must_use]
pub fn from_point(point: $point_ty<T>) -> Self {
bytemuck::cast(point)
}
#[doc = "Convert to point."]
#[inline]
#[must_use]
pub fn to_point(self) -> $point_ty<T> {
bytemuck::cast(self)
}
#[doc = "Reinterpret as point."]
#[inline]
#[must_use]
pub fn as_point(&self) -> &$point_ty<T> {
bytemuck::cast_ref(self)
}
#[doc = "Reinterpret as point."]
#[inline]
#[must_use]
pub fn as_point_mut(&mut self) -> &mut $point_ty<T> {
bytemuck::cast_mut(self)
}
$(
#[doc = "Instantiate from size."]
#[inline]
#[must_use]
pub fn from_size(size: $size_ty<T>) -> Self {
bytemuck::cast(size)
}
#[doc = "Convert to size."]
#[inline]
#[must_use]
pub fn to_size(self) -> $size_ty<T> {
bytemuck::cast(self)
}
#[doc = "Reinterpret as size."]
#[inline]
#[must_use]
pub fn as_size(&self) -> &$size_ty<T> {
bytemuck::cast_ref(self)
}
#[doc = "Reinterpret as size."]
#[inline]
#[must_use]
pub fn as_size_mut(&mut self) -> &mut $size_ty<T> {
bytemuck::cast_mut(self)
}
)*
};
}
macro_rules! implement_swizzle {
($base_type_name:ident) => {
impl<T: Unit> Swizzle<T> for $base_type_name<T> {
#[inline]
fn swizzle2<const X: usize, const Y: usize>(&self) -> Vector2<T> {
[self.const_get::<X>(), self.const_get::<Y>()].into()
}
#[inline]
fn swizzle3<const X: usize, const Y: usize, const Z: usize>(&self) -> Vector3<T> {
[
self.const_get::<X>(),
self.const_get::<Y>(),
self.const_get::<Z>(),
]
.into()
}
#[inline]
fn swizzle4<const X: usize, const Y: usize, const Z: usize, const W: usize>(
&self,
) -> Vector4<T> {
[
self.const_get::<X>(),
self.const_get::<Y>(),
self.const_get::<Z>(),
self.const_get::<W>(),
]
.into()
}
}
};
}
crate::forward_op_to_raw!(Vector2, Add<Self>::add -> Self);
crate::forward_op_to_raw!(Vector3, Add<Self>::add -> Self);
crate::forward_op_to_raw!(Vector4, Add<Self>::add -> Self);
crate::forward_op_to_raw!(Vector2, Sub<Self>::sub -> Self);
crate::forward_op_to_raw!(Vector3, Sub<Self>::sub -> Self);
crate::forward_op_to_raw!(Vector4, Sub<Self>::sub -> Self);
crate::forward_op_to_raw!(Vector2, Mul<Self>::mul -> Self);
crate::forward_op_to_raw!(Vector3, Mul<Self>::mul -> Self);
crate::forward_op_to_raw!(Vector4, Mul<Self>::mul -> Self);
crate::forward_op_to_raw!(Vector2, Div<Self>::div -> Self);
crate::forward_op_to_raw!(Vector3, Div<Self>::div -> Self);
crate::forward_op_to_raw!(Vector4, Div<Self>::div -> Self);
crate::forward_op_to_raw!(Vector2, Rem<Self>::rem -> Self);
crate::forward_op_to_raw!(Vector3, Rem<Self>::rem -> Self);
crate::forward_op_to_raw!(Vector4, Rem<Self>::rem -> Self);
crate::forward_neg_to_raw!(Vector2);
crate::forward_neg_to_raw!(Vector3);
crate::forward_neg_to_raw!(Vector4);
crate::forward_op_to_raw!(Vector2, Mul<[f32, f64, i32, u32]>::mul -> Self);
crate::forward_op_to_raw!(Vector3, Mul<[f32, f64, i32, u32]>::mul -> Self);
crate::forward_op_to_raw!(Vector4, Mul<[f32, f64, i32, u32]>::mul -> Self);
crate::forward_op_to_raw!(Vector2, Div<[f32, f64, i32, u32]>::div -> Self);
crate::forward_op_to_raw!(Vector3, Div<[f32, f64, i32, u32]>::div -> Self);
crate::forward_op_to_raw!(Vector4, Div<[f32, f64, i32, u32]>::div -> Self);
crate::forward_op_to_raw!(Vector2, Rem<[f32, f64, i32, u32]>::rem -> Self);
crate::forward_op_to_raw!(Vector3, Rem<[f32, f64, i32, u32]>::rem -> Self);
crate::forward_op_to_raw!(Vector4, Rem<[f32, f64, i32, u32]>::rem -> Self);
crate::forward_op_assign_to_raw!(Vector2, AddAssign<Self>::add_assign);
crate::forward_op_assign_to_raw!(Vector3, AddAssign<Self>::add_assign);
crate::forward_op_assign_to_raw!(Vector4, AddAssign<Self>::add_assign);
crate::forward_op_assign_to_raw!(Vector2, SubAssign<Self>::sub_assign);
crate::forward_op_assign_to_raw!(Vector3, SubAssign<Self>::sub_assign);
crate::forward_op_assign_to_raw!(Vector4, SubAssign<Self>::sub_assign);
crate::forward_op_assign_to_raw!(Vector2, MulAssign<Self>::mul_assign);
crate::forward_op_assign_to_raw!(Vector3, MulAssign<Self>::mul_assign);
crate::forward_op_assign_to_raw!(Vector4, MulAssign<Self>::mul_assign);
crate::forward_op_assign_to_raw!(Vector2, DivAssign<Self>::div_assign);
crate::forward_op_assign_to_raw!(Vector3, DivAssign<Self>::div_assign);
crate::forward_op_assign_to_raw!(Vector4, DivAssign<Self>::div_assign);
crate::forward_op_assign_to_raw!(Vector2, RemAssign<Self>::rem_assign);
crate::forward_op_assign_to_raw!(Vector3, RemAssign<Self>::rem_assign);
crate::forward_op_assign_to_raw!(Vector4, RemAssign<Self>::rem_assign);
crate::forward_op_assign_to_raw!(Vector2, AddAssign<[f32, f64, i32, u32]>::add_assign);
crate::forward_op_assign_to_raw!(Vector3, AddAssign<[f32, f64, i32, u32]>::add_assign);
crate::forward_op_assign_to_raw!(Vector4, AddAssign<[f32, f64, i32, u32]>::add_assign);
crate::forward_op_assign_to_raw!(Vector2, SubAssign<[f32, f64, i32, u32]>::sub_assign);
crate::forward_op_assign_to_raw!(Vector3, SubAssign<[f32, f64, i32, u32]>::sub_assign);
crate::forward_op_assign_to_raw!(Vector4, SubAssign<[f32, f64, i32, u32]>::sub_assign);
crate::forward_op_assign_to_raw!(Vector2, MulAssign<[f32, f64, i32, u32]>::mul_assign);
crate::forward_op_assign_to_raw!(Vector3, MulAssign<[f32, f64, i32, u32]>::mul_assign);
crate::forward_op_assign_to_raw!(Vector4, MulAssign<[f32, f64, i32, u32]>::mul_assign);
crate::forward_op_assign_to_raw!(Vector2, DivAssign<[f32, f64, i32, u32]>::div_assign);
crate::forward_op_assign_to_raw!(Vector3, DivAssign<[f32, f64, i32, u32]>::div_assign);
crate::forward_op_assign_to_raw!(Vector4, DivAssign<[f32, f64, i32, u32]>::div_assign);
crate::forward_op_assign_to_raw!(Vector2, RemAssign<[f32, f64, i32, u32]>::rem_assign);
crate::forward_op_assign_to_raw!(Vector3, RemAssign<[f32, f64, i32, u32]>::rem_assign);
crate::forward_op_assign_to_raw!(Vector4, RemAssign<[f32, f64, i32, u32]>::rem_assign);
crate::derive_standard_traits!(Vector2 {
x: T::Scalar,
y: T::Scalar
});
crate::derive_standard_traits!(Vector3 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar
});
crate::derive_standard_traits!(Vector4 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar,
w: T::Scalar
});
crate::derive_array_conversion_traits!(Vector2, 2);
crate::derive_array_conversion_traits!(Vector3, 3);
crate::derive_array_conversion_traits!(Vector4, 4);
crate::derive_tuple_conversion_traits!(Vector2 {
x: T::Scalar,
y: T::Scalar
});
crate::derive_tuple_conversion_traits!(Vector3 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar
});
crate::derive_tuple_conversion_traits!(Vector4 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar,
w: T::Scalar
});
crate::derive_glam_conversion_traits!(Vector2 {
x: T::Scalar,
y: T::Scalar
});
crate::derive_glam_conversion_traits!(Vector3 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar
});
crate::derive_glam_conversion_traits!(Vector4 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar,
w: T::Scalar
});
implement_swizzle!(Vector2);
implement_swizzle!(Vector3);
implement_swizzle!(Vector4);
impl<T: Unit> Vector2<T> {
pub const ZERO: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
};
pub const ONE: Self = Self {
x: T::Scalar::ONE,
y: T::Scalar::ONE,
};
pub const X: Self = Vector2 {
x: T::Scalar::ONE,
y: T::Scalar::ZERO,
};
pub const Y: Self = Vector2 {
x: T::Scalar::ZERO,
y: T::Scalar::ONE,
};
pub const AXES: [Self; 2] = [Self::X, Self::Y];
pub const fn new(x: T::Scalar, y: T::Scalar) -> Self {
Self { x, y }
}
crate::forward_constructors!(2, glam::Vec2);
crate::forward_comparison!(
<<T::Scalar as Scalar>::Vec2 as crate::bindings::Vector>::Mask,
glam::Vec2
);
crate::casting_interface!(Vector2 {
x: T::Scalar,
y: T::Scalar
});
crate::tuple_interface!(Vector2 {
x: T::Scalar,
y: T::Scalar
});
crate::array_interface!(2);
crate::forward_to_raw!(
glam::Vec2 =>
#[doc = "Dot product"]
pub fn dot(self, other: Self) -> T::Scalar;
#[doc = "Extend with z-component to [`Vector3`]."]
pub fn extend(self, z: T::Scalar) -> Vector3<T>;
);
#[inline]
#[must_use]
pub fn swizzle<const X: usize, const Y: usize>(&self) -> Self {
self.swizzle2::<X, Y>()
}
vector_interface!(Point2, Size2);
}
impl<T> Vector2<T>
where
T: Unit,
T::Scalar: FloatScalar,
{
pub const NAN: Self = Vector2 {
x: <T::Scalar as FloatScalar>::NAN,
y: <T::Scalar as FloatScalar>::NAN,
};
crate::forward_float_ops!(
<<T::Scalar as Scalar>::Vec2 as crate::bindings::Vector>::Mask,
glam::Vec2
);
crate::forward_float_vector_ops!(glam::Vec2);
crate::forward_to_raw!(
glam::Vec2 =>
#[doc = "Return `(sin(angle), cos(angle)`."]
pub fn from_angle(angle: Angle<T::Scalar>) -> Vector2<T::Scalar>;
#[doc = "Rotate by a vector containing `(sin(angle), cos(angle))`"]
pub fn rotate(self, rotation: Vector2<T::Scalar>) -> Self;
#[doc = "Angle between this and another vector."]
pub fn angle_between(self, other: Self) -> Angle<T::Scalar>;
);
}
impl<T> Vector2<T>
where
T: Unit,
T::Scalar: SignedScalar,
{
pub const NEG_ONE: Self = Vector2 {
x: T::Scalar::NEG_ONE,
y: T::Scalar::NEG_ONE,
};
pub const NEG_X: Self = Vector2 {
x: T::Scalar::NEG_ONE,
y: T::Scalar::ZERO,
};
pub const NEG_Y: Self = Vector2 {
x: T::Scalar::ZERO,
y: T::Scalar::NEG_ONE,
};
crate::forward_to_raw!(
glam::Vec2 =>
#[doc = "Turn all components positive."]
pub fn abs(self) -> Self;
#[doc = "Return a vector where each component is 1 or -1 depending on the sign of the input."]
pub fn signum(self) -> Self;
#[doc = "Get the perpendicular vector."]
pub fn perp(self) -> Self;
#[doc(alias = "wedge")]
#[doc(alias = "cross")]
#[doc(alias = "determinant")]
#[doc = "Perpendicular dot product"]
pub fn perp_dot(self, other: Self) -> T::Scalar;
);
}
impl<T: Unit> Vector3<T> {
pub const ZERO: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
};
pub const ONE: Self = Self {
x: T::Scalar::ONE,
y: T::Scalar::ONE,
z: T::Scalar::ONE,
};
pub const X: Self = Self {
x: T::Scalar::ONE,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
};
pub const Y: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ONE,
z: T::Scalar::ZERO,
};
pub const Z: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::ONE,
};
pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
pub const fn new(x: T::Scalar, y: T::Scalar, z: T::Scalar) -> Self {
Self { x, y, z }
}
crate::forward_constructors!(3, glam::Vec3);
crate::forward_comparison!(
<<T::Scalar as Scalar>::Vec3 as crate::bindings::Vector>::Mask,
glam::Vec3
);
crate::casting_interface!(Vector3 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar
});
crate::tuple_interface!(Vector3 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar
});
crate::array_interface!(3);
crate::forward_to_raw!(
glam::Vec3 =>
#[doc = "Dot product"]
pub fn dot(self, other: Self) -> T::Scalar;
#[doc = "Extend with w-component to [`Vector4`]."]
pub fn extend(self, w: T::Scalar) -> Vector4<T>;
);
#[inline]
#[must_use]
pub fn swizzle<const X: usize, const Y: usize, const Z: usize>(&self) -> Self {
self.swizzle3::<X, Y, Z>()
}
vector_interface!(Point3, Size3);
}
impl<T> Vector3<T>
where
T: Unit,
T::Scalar: FloatScalar,
{
pub const NAN: Self = Vector3 {
x: <T::Scalar as FloatScalar>::NAN,
y: <T::Scalar as FloatScalar>::NAN,
z: <T::Scalar as FloatScalar>::NAN,
};
crate::forward_float_ops!(
<<T::Scalar as Scalar>::Vec3 as crate::bindings::Vector>::Mask,
glam::Vec3
);
crate::forward_float_vector_ops!(glam::Vec3);
crate::forward_to_raw!(
glam::Vec3 =>
#[doc = "Angle between this and another vector."]
pub fn angle_between(self, other: Self) -> Angle<T::Scalar>;
#[doc = "See (e.g.) [`glam::Vec3::any_orthogonal_vector()`]."]
pub fn any_orthogonal_vector(&self) -> Self;
#[doc = "See (e.g.) [`glam::Vec3::any_orthonormal_vector()`]."]
pub fn any_orthonormal_vector(&self) -> Self;
#[doc = "See (e.g.) [`glam::Vec3::any_orthonormal_pair()`]."]
pub fn any_orthonormal_pair(&self) -> (Self, Self);
#[doc = "Cross product"]
pub fn cross(self, other: Self) -> Self;
);
}
impl<T> Vector3<T>
where
T: Unit,
T::Scalar: SignedScalar,
{
pub const NEG_ONE: Self = Vector3 {
x: T::Scalar::NEG_ONE,
y: T::Scalar::NEG_ONE,
z: T::Scalar::NEG_ONE,
};
pub const NEG_X: Self = Vector3 {
x: T::Scalar::NEG_ONE,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
};
pub const NEG_Y: Self = Vector3 {
x: T::Scalar::ZERO,
y: T::Scalar::NEG_ONE,
z: T::Scalar::ZERO,
};
pub const NEG_Z: Self = Vector3 {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::NEG_ONE,
};
crate::forward_to_raw!(
glam::Vec3 =>
#[doc = "Turn all components positive."]
pub fn abs(self) -> Self;
#[doc = "Return a vector where each component is 1 or -1 depending on the sign of the input."]
pub fn signum(self) -> Self;
);
}
impl<T> Vector3<T>
where
T: Unit<Scalar = f32>,
{
#[inline]
#[must_use]
pub fn from_vec3a(vec: glam::Vec3A) -> Self {
vec.into()
}
#[inline]
#[must_use]
pub fn to_vec3a(self) -> glam::Vec3A {
self.into()
}
}
impl<T: Unit> Vector4<T> {
pub const ZERO: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
w: T::Scalar::ZERO,
};
pub const ONE: Self = Self {
x: T::Scalar::ONE,
y: T::Scalar::ONE,
z: T::Scalar::ONE,
w: T::Scalar::ONE,
};
pub const X: Self = Self {
x: T::Scalar::ONE,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
w: T::Scalar::ZERO,
};
pub const Y: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ONE,
z: T::Scalar::ZERO,
w: T::Scalar::ZERO,
};
pub const Z: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::ONE,
w: T::Scalar::ZERO,
};
pub const W: Self = Self {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
w: T::Scalar::ONE,
};
pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W];
pub const fn new(x: T::Scalar, y: T::Scalar, z: T::Scalar, w: T::Scalar) -> Self {
Self { x, y, z, w }
}
crate::forward_constructors!(4, glam::Vec4);
crate::forward_comparison!(
<<T::Scalar as Scalar>::Vec4 as crate::bindings::Vector>::Mask,
glam::Vec4
);
crate::casting_interface!(Vector4 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar,
w: T::Scalar
});
crate::tuple_interface!(Vector4 {
x: T::Scalar,
y: T::Scalar,
z: T::Scalar,
w: T::Scalar
});
crate::array_interface!(4);
crate::forward_to_raw!(
glam::Vec4 =>
#[doc = "Dot product"]
pub fn dot(self, other: Self) -> T::Scalar;
);
#[inline]
#[must_use]
pub fn swizzle<const X: usize, const Y: usize, const Z: usize, const W: usize>(&self) -> Self {
self.swizzle4::<X, Y, Z, W>()
}
vector_interface!(Point4);
}
impl<T> Vector4<T>
where
T: Unit,
T::Scalar: FloatScalar,
{
pub const NAN: Self = Vector4 {
x: <T::Scalar as FloatScalar>::NAN,
y: <T::Scalar as FloatScalar>::NAN,
z: <T::Scalar as FloatScalar>::NAN,
w: <T::Scalar as FloatScalar>::NAN,
};
crate::forward_float_ops!(
<<T::Scalar as Scalar>::Vec4 as crate::bindings::Vector>::Mask,
glam::Vec4
);
crate::forward_float_vector_ops!(glam::Vec4);
}
impl<T> Vector4<T>
where
T: Unit,
T::Scalar: SignedScalar,
{
pub const NEG_ONE: Self = Vector4 {
x: T::Scalar::NEG_ONE,
y: T::Scalar::NEG_ONE,
z: T::Scalar::NEG_ONE,
w: T::Scalar::NEG_ONE,
};
pub const NEG_X: Self = Vector4 {
x: T::Scalar::NEG_ONE,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
w: T::Scalar::ZERO,
};
pub const NEG_Y: Self = Vector4 {
x: T::Scalar::ZERO,
y: T::Scalar::NEG_ONE,
z: T::Scalar::ZERO,
w: T::Scalar::ZERO,
};
pub const NEG_Z: Self = Vector4 {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::NEG_ONE,
w: T::Scalar::ZERO,
};
pub const NEG_W: Self = Vector4 {
x: T::Scalar::ZERO,
y: T::Scalar::ZERO,
z: T::Scalar::ZERO,
w: T::Scalar::NEG_ONE,
};
crate::forward_to_raw!(
glam::Vec4 =>
#[doc = "Turn all components positive."]
pub fn abs(self) -> Self;
#[doc = "Return a vector where each component is 1 or -1 depending on the sign of the input."]
pub fn signum(self) -> Self;
);
}
impl<T: Unit> ToRaw for Vector2<T> {
type Raw = <T::Scalar as Scalar>::Vec2;
#[inline]
fn to_raw(self) -> Self::Raw {
bytemuck::cast(self)
}
}
impl<T: Unit> FromRaw for Vector2<T> {
#[inline]
fn from_raw(raw: Self::Raw) -> Self {
bytemuck::cast(raw)
}
}
impl<T: Unit> AsRaw for Vector2<T> {
#[inline]
fn as_raw(&self) -> &Self::Raw {
bytemuck::cast_ref(self)
}
#[inline]
fn as_raw_mut(&mut self) -> &mut Self::Raw {
bytemuck::cast_mut(self)
}
}
impl<T: Unit> ToRaw for Vector3<T> {
type Raw = <T::Scalar as Scalar>::Vec3;
#[inline]
fn to_raw(self) -> Self::Raw {
bytemuck::cast(self)
}
}
impl<T: Unit> FromRaw for Vector3<T> {
#[inline]
fn from_raw(raw: Self::Raw) -> Self {
bytemuck::cast(raw)
}
}
impl<T: Unit> AsRaw for Vector3<T> {
#[inline]
fn as_raw(&self) -> &Self::Raw {
bytemuck::cast_ref(self)
}
#[inline]
fn as_raw_mut(&mut self) -> &mut Self::Raw {
bytemuck::cast_mut(self)
}
}
impl<T: Unit> ToRaw for Vector4<T> {
type Raw = <T::Scalar as Scalar>::Vec4;
#[inline]
fn to_raw(self) -> Self::Raw {
bytemuck::cast(self)
}
}
impl<T: Unit> FromRaw for Vector4<T> {
#[inline]
fn from_raw(raw: Self::Raw) -> Self {
bytemuck::cast(raw)
}
}
impl<T: Unit> AsRaw for Vector4<T> {
#[inline]
fn as_raw(&self) -> &Self::Raw {
bytemuck::cast_ref(self)
}
#[inline]
fn as_raw_mut(&mut self) -> &mut Self::Raw {
bytemuck::cast_mut(self)
}
}
impl<T> From<glam::Vec3A> for Vector3<T>
where
T: Unit<Scalar = f32>,
{
#[inline]
fn from(v: glam::Vec3A) -> Self {
Self::from_raw(v.into())
}
}
impl<T> From<Vector3<T>> for glam::Vec3A
where
T: Unit<Scalar = f32>,
{
#[inline]
fn from(v: Vector3<T>) -> Self {
v.to_raw().into()
}
}
impl<T> Mul<Vector3<T>> for glam::Quat
where
T: Unit<Scalar = f32>,
T::Scalar: FloatScalar<Vec3f = glam::Vec3>,
{
type Output = Vector3<T>;
#[inline]
fn mul(self, rhs: Vector3<T>) -> Self::Output {
Vector3::from_raw(self * rhs.to_raw())
}
}
impl<T> Mul<Vector3<T>> for glam::DQuat
where
T: Unit<Scalar = f64>,
T::Scalar: FloatScalar<Vec3f = glam::DVec3>,
{
type Output = Vector3<T>;
#[inline]
fn mul(self, rhs: Vector3<T>) -> Self::Output {
Vector3::from_raw(self * rhs.to_raw())
}
}
impl<'a, T: Unit> Sum<&'a Vector2<T>> for Vector2<T> {
#[inline]
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
Self::from_raw(iter.map(AsRaw::as_raw).sum())
}
}
impl<'a, T: Unit> Sum<&'a Vector3<T>> for Vector3<T> {
#[inline]
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
Self::from_raw(iter.map(AsRaw::as_raw).sum())
}
}
impl<'a, T: Unit> Sum<&'a Vector4<T>> for Vector4<T> {
#[inline]
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
Self::from_raw(iter.map(AsRaw::as_raw).sum())
}
}
#[cfg(test)]
mod tests {
use approx::assert_abs_diff_eq;
use crate::{vector, AngleConsts};
use super::*;
struct F32;
impl Unit for F32 {
type Scalar = f32;
}
struct F64;
impl Unit for F64 {
type Scalar = f64;
}
struct I32;
impl Unit for I32 {
type Scalar = i32;
}
struct U32;
impl Unit for U32 {
type Scalar = u32;
}
type Vec2 = Vector2<F32>;
type Vec3 = Vector3<F32>;
type Vec4 = Vector4<F32>;
type DVec2 = Vector2<F64>;
type DVec3 = Vector3<F64>;
type DVec4 = Vector4<F64>;
type IVec2 = Vector2<I32>;
type IVec3 = Vector3<I32>;
type IVec4 = Vector4<I32>;
type UVec2 = Vector2<U32>;
type UVec3 = Vector3<U32>;
type UVec4 = Vector4<U32>;
macro_rules! check_splat {
($value:expr, $op:ident, $expected:expr) => {
assert_eq!(Vec2::splat($value).$op(), Vec2::splat($expected));
assert_eq!(Vec3::splat($value).$op(), Vec3::splat($expected));
assert_eq!(Vec4::splat($value).$op(), Vec4::splat($expected));
assert_eq!(DVec2::splat($value).$op(), DVec2::splat($expected));
assert_eq!(DVec3::splat($value).$op(), DVec3::splat($expected));
assert_eq!(DVec4::splat($value).$op(), DVec4::splat($expected));
};
($value:expr, $op:ident ( $arg:expr ), $expected:expr) => {
assert_eq!(
Vec2::splat($value).$op(Vec2::splat($arg)),
Vec2::splat($expected)
);
assert_eq!(
Vec3::splat($value).$op(Vec3::splat($arg)),
Vec3::splat($expected)
);
assert_eq!(
Vec4::splat($value).$op(Vec4::splat($arg)),
Vec4::splat($expected)
);
assert_eq!(
DVec2::splat($value).$op(DVec2::splat($arg)),
DVec2::splat($expected)
);
assert_eq!(
DVec3::splat($value).$op(DVec3::splat($arg)),
DVec3::splat($expected)
);
assert_eq!(
DVec4::splat($value).$op(DVec4::splat($arg)),
DVec4::splat($expected)
);
};
}
macro_rules! check_splat_ints {
($value:expr, $op:ident, $expected:expr) => {
check_splat!($value as _, $op, $expected as _);
assert_eq!(IVec2::splat($value).$op(), IVec2::splat($expected));
assert_eq!(IVec3::splat($value).$op(), IVec3::splat($expected));
assert_eq!(IVec4::splat($value).$op(), IVec4::splat($expected));
assert_eq!(UVec2::splat($value).$op(), UVec2::splat($expected));
assert_eq!(UVec3::splat($value).$op(), UVec3::splat($expected));
assert_eq!(UVec4::splat($value).$op(), UVec4::splat($expected));
};
($value:expr, $op:ident ( $arg:expr ), $expected:expr) => {
assert_eq!(
IVec2::splat($value).$op(IVec2::splat($arg)),
IVec2::splat($expected)
);
assert_eq!(
IVec3::splat($value).$op(IVec3::splat($arg)),
IVec3::splat($expected)
);
assert_eq!(
IVec4::splat($value).$op(IVec4::splat($arg)),
IVec4::splat($expected)
);
assert_eq!(
UVec2::splat($value).$op(UVec2::splat($arg)),
UVec2::splat($expected)
);
assert_eq!(
UVec3::splat($value).$op(UVec3::splat($arg)),
UVec3::splat($expected)
);
assert_eq!(
UVec4::splat($value).$op(UVec4::splat($arg)),
UVec4::splat($expected)
);
};
}
#[test]
fn round() {
check_splat!(1.4, round, 1.0);
check_splat!(1.6, round, 2.0);
check_splat!(1.5, round, 2.0);
check_splat!(1.49999, round, 1.0);
}
#[test]
fn ceil() {
check_splat!(1.4, ceil, 2.0);
check_splat!(1.6, ceil, 2.0);
check_splat!(1.5, ceil, 2.0);
}
#[test]
fn floor() {
check_splat!(1.4, floor, 1.0);
check_splat!(1.6, floor, 1.0);
check_splat!(1.5, floor, 1.0);
}
#[test]
fn arithmetic() {
use core::ops::{Add, Div, Sub};
check_splat_ints!(2, div(1), 2);
check_splat_ints!(10, div(2), 5);
check_splat!(2.0, mul(2.5), 2.0 * 2.5);
check_splat_ints!(10, mul(2), 20);
check_splat_ints!(2, add(1), 3);
check_splat_ints!(10, add(2), 12);
check_splat_ints!(2, sub(1), 1);
check_splat_ints!(10, sub(2), 8);
let mut v: Vector4<f32> = vector!(1.0, 2.0, 3.0, 4.0);
v *= Vector4::splat(2.0);
assert_eq!(v, (2.0, 4.0, 6.0, 8.0));
v /= Vector4::splat(2.0);
assert_eq!(v, (1.0, 2.0, 3.0, 4.0));
v += Vector4::splat(1.0);
assert_eq!(v, (2.0, 3.0, 4.0, 5.0));
v -= Vector4::splat(2.0);
assert_eq!(v, (0.0, 1.0, 2.0, 3.0));
v %= Vector4::splat(2.0);
assert_eq!(v, (0.0, 1.0, 0.0, 1.0));
}
#[test]
fn sum() {
let a: Vector4<f32> = vector!(1.0, 2.0, 3.0, 4.0);
let b: Vector4<f32> = vector!(1.0, 2.0, 3.0, 4.0);
let c: Vector4<f32> = vector!(1.0, 2.0, 3.0, 4.0);
let d: Vector4<f32> = vector!(1.0, 2.0, 3.0, 4.0);
let sum: Vector4<f32> = [a, b, c, d].iter().sum();
assert_eq!(sum, (4.0, 8.0, 12.0, 16.0));
}
#[test]
fn lerp() {
let a = Vec2 { x: 1.0, y: 2.0 };
let b = Vec2 { x: 2.0, y: 3.0 };
assert_eq!(a.lerp(b, 0.0), a);
assert_eq!(a.lerp(b, 0.5), (1.5, 2.5));
assert_eq!(a.lerp(b, 1.0), b);
}
#[test]
fn const_construction() {
const CONST_VEC: Vec2 = Vector2 { x: 1.0, y: 2.0 };
static STATIC_VEC: Vec2 = Vector2 { x: 2.0, y: 3.0 };
assert_eq!(CONST_VEC, (1.0, 2.0));
assert_eq!(STATIC_VEC, (2.0, 3.0));
}
#[test]
fn units() {
use crate::vector;
assert_abs_diff_eq!(Vec2::X, vector!(1.0, 0.0));
assert_abs_diff_eq!(Vec2::Y, vector!(0.0, 1.0));
assert_abs_diff_eq!(Vec3::X, vector!(1.0, 0.0, 0.0));
assert_abs_diff_eq!(Vec3::Y, vector!(0.0, 1.0, 0.0));
assert_abs_diff_eq!(Vec3::Z, vector!(0.0, 0.0, 1.0));
assert_abs_diff_eq!(Vec4::X, vector!(1.0, 0.0, 0.0, 0.0));
assert_abs_diff_eq!(Vec4::Y, vector!(0.0, 1.0, 0.0, 0.0));
assert_abs_diff_eq!(Vec4::Z, vector!(0.0, 0.0, 1.0, 0.0));
assert_abs_diff_eq!(Vec4::W, vector!(0.0, 0.0, 0.0, 1.0));
}
#[test]
fn nan() {
let v2 = Vec2::new(1.0, core::f32::NAN);
assert!(v2.is_nan());
assert!(!v2.is_finite());
assert_eq!(v2.is_nan_mask(), <f32 as Scalar>::BVec2::new(false, true));
let v3 = Vec3::new(1.0, core::f32::NAN, 3.0);
assert!(v3.is_nan());
assert!(!v3.is_finite());
assert_eq!(
v3.is_nan_mask(),
<f32 as Scalar>::BVec3::new(false, true, false)
);
let v4 = Vec4::new(1.0, 2.0, core::f32::NAN, 4.0);
assert!(v4.is_nan());
assert!(!v4.is_finite());
assert_eq!(
v4.is_nan_mask(),
<f32 as Scalar>::BVec4::new(false, false, true, false)
);
assert!(Vec2::NAN.is_nan());
assert!(Vec3::NAN.is_nan());
assert!(Vec4::NAN.is_nan());
let v = Vec4::select(v4.is_nan_mask(), Vec4::ZERO, v4);
assert_eq!(v, (1.0, 2.0, 0.0, 4.0));
}
#[test]
fn swizzle2() {
assert_eq!(Vec2::X.swizzle::<1, 0>(), (0.0, 1.0));
assert_eq!(
Vec3::new(1.0, 2.0, 3.0).swizzle2::<1, 0>(),
Vec2::new(2.0, 1.0)
);
}
#[test]
fn swizzle3() {
assert_eq!(
Vec3::new(1.0, 2.0, 3.0).swizzle::<2, 1, 0>(),
(3.0, 2.0, 1.0)
);
assert_eq!(Vec2::X.swizzle3::<1, 0, 1>(), Vec3::new(0.0, 1.0, 0.0));
assert_eq!(
Vec4::new(1.0, 2.0, 3.0, 4.0).swizzle3::<3, 2, 1>(),
Vec3::new(4.0, 3.0, 2.0)
);
}
#[test]
fn swizzle4() {
assert_eq!(
Vec4::new(0.0, 1.0, 2.0, 3.0).swizzle::<3, 2, 1, 0>(),
(3.0, 2.0, 1.0, 0.0)
);
assert_eq!(
Vec2::X.swizzle4::<1, 0, 1, 0>(),
Vec4::new(0.0, 1.0, 0.0, 1.0)
);
assert_eq!(
Vec3::new(0.0, 1.0, 2.0).swizzle4::<2, 1, 0, 2>(),
Vec4::new(2.0, 1.0, 0.0, 2.0)
);
}
#[test]
fn to_3d() {
let v = Vec2 { x: 3.0, y: 4.0 };
assert_eq!(v.extend(2.0), crate::vec3!(3.0, 4.0, 2.0));
}
#[test]
fn to_4d() {
assert_eq!(Vec3::Z.extend(2.0), Vec4::new(0.0, 0.0, 1.0, 2.0));
}
#[test]
fn vec3a() {
let a: glam::Vec3A = Vec3::new(0.0, 1.0, 2.0).to_vec3a();
assert_eq!(a, glam::Vec3A::new(0.0, 1.0, 2.0));
let b = Vec3::from_vec3a(a);
assert_eq!(b, Vec3::new(0.0, 1.0, 2.0));
}
#[test]
fn scaling_by_scalar() {
{
let x: Vec4 = (1.0, 2.0, 3.0, 4.0).into();
let mut a = x;
let mut b = x;
let mut c = x;
a *= 2.0;
b /= 2.0;
c %= 2.0;
assert_eq!(a, (2.0, 4.0, 6.0, 8.0));
assert_eq!(b, (0.5, 1.0, 1.5, 2.0));
assert_eq!(c, (1.0, 0.0, 1.0, 0.0));
}
{
let x: DVec4 = (1.0, 2.0, 3.0, 4.0).into();
let a = x * 2.0;
let b = x / 2.0;
assert_eq!(a, (2.0, 4.0, 6.0, 8.0));
assert_eq!(b, (0.5, 1.0, 1.5, 2.0));
}
{
let x: IVec4 = (1, 2, 3, 4).into();
let a = x * 2;
let b = x / 2;
assert_eq!(a, (2, 4, 6, 8));
assert_eq!(b, (0, 1, 1, 2));
}
{
let x: UVec4 = (1, 2, 3, 4).into();
let a = x * 2;
let b = x / 2;
assert_eq!(a, (2, 4, 6, 8));
assert_eq!(b, (0, 1, 1, 2));
}
}
#[test]
fn cmp() {
let a = Vec4::new(1.0, 2.0, 3.0, 4.0);
let b = Vec4::new(4.0, 2.0, 1.0, 3.0);
let eq = a.cmpeq(b);
let ne = a.cmpne(b);
let lt = a.cmplt(b);
let le = a.cmple(b);
let gt = a.cmpgt(b);
let ge = a.cmpge(b);
assert_eq!(eq, <f32 as Scalar>::BVec4::new(false, true, false, false));
assert_eq!(ne, <f32 as Scalar>::BVec4::new(true, false, true, true));
assert_eq!(lt, <f32 as Scalar>::BVec4::new(true, false, false, false));
assert_eq!(le, <f32 as Scalar>::BVec4::new(true, true, false, false));
assert_eq!(gt, <f32 as Scalar>::BVec4::new(false, false, true, true));
assert_eq!(ge, <f32 as Scalar>::BVec4::new(false, true, true, true));
assert_eq!(a.min(b), [1.0, 2.0, 1.0, 3.0]);
assert_eq!(a.max(b), [4.0, 2.0, 3.0, 4.0]);
assert_eq!(a.min_element(), 1.0);
assert_eq!(a.max_element(), 4.0);
}
#[test]
fn cmp_f64() {
let a = Vector4::<f64>::new(1.0, 2.0, 3.0, 4.0);
let b = Vector4::<f64>::new(4.0, 2.0, 1.0, 3.0);
let eq = a.cmpeq(b);
let ne = a.cmpne(b);
let lt = a.cmplt(b);
let le = a.cmple(b);
let gt = a.cmpgt(b);
let ge = a.cmpge(b);
assert_eq!(eq, <f64 as Scalar>::BVec4::new(false, true, false, false));
assert_eq!(ne, <f64 as Scalar>::BVec4::new(true, false, true, true));
assert_eq!(lt, <f64 as Scalar>::BVec4::new(true, false, false, false));
assert_eq!(le, <f64 as Scalar>::BVec4::new(true, true, false, false));
assert_eq!(gt, <f64 as Scalar>::BVec4::new(false, false, true, true));
assert_eq!(ge, <f64 as Scalar>::BVec4::new(false, true, true, true));
assert_eq!(a.min(b), [1.0, 2.0, 1.0, 3.0]);
assert_eq!(a.max(b), [4.0, 2.0, 3.0, 4.0]);
assert_eq!(a.min_element(), 1.0);
assert_eq!(a.max_element(), 4.0);
}
#[test]
fn clamp() {
let a = Vec4::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(
a.clamp(Vec4::splat(2.0), Vec4::splat(3.5)),
Vec4::new(2.0, 2.0, 3.0, 3.5)
);
let b = IVec4::new(1, 2, 3, 5);
assert_eq!(b.clamp(IVec4::splat(2), IVec4::splat(4)), (2, 2, 3, 4));
}
#[test]
fn dot() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(2.0, 3.0, 4.0);
assert_abs_diff_eq!(a.dot(b), 20.0);
}
#[test]
fn normalize() {
let a = Vec3::new(1.0, 1.0, 2.0);
assert!(!a.is_normalized());
let d = a.dot(a).sqrt();
let b = a / Vec3::splat(d);
assert_abs_diff_eq!(a.normalize(), b);
assert!(a.normalize().is_normalized());
let z = Vec3::ZERO;
assert_eq!(z.normalize_or_zero(), Vec3::ZERO);
}
#[test]
fn length() {
let v = Vec3::new(1.0, 2.0, 3.0);
let u = glam::Vec3::new(1.0, 2.0, 3.0);
assert_eq!(v.length(), u.length());
assert_abs_diff_eq!(
v.length_squared(),
u.length() * u.length(),
epsilon = 0.00001
);
}
#[test]
fn exp() {
let a = Vec3::splat(1.0);
assert_eq!(a.exp(), Vec3::splat(1.0f32.exp()));
}
#[test]
fn powf() {
let a = Vec3::splat(2.0);
assert_eq!(a.powf(2.0), Vec3::splat(4.0));
}
#[test]
fn recip() {
let a = Vec3::splat(2.0);
assert_eq!(a.recip(), Vec3::splat(0.5));
}
#[test]
fn mul_add() {
let a = Vec3::new(1.0, 2.0, 3.0);
let b = Vec3::new(2.0, 3.0, 4.0);
let c = Vec3::new(3.0, 4.0, 5.0);
assert_eq!(a.mul_add(b, c), a * b + c);
}
#[test]
fn abs() {
let a = Vec3::new(1.0, -2.0, -3.0);
assert_eq!(a.abs(), (1.0, 2.0, 3.0));
}
#[test]
fn signum() {
let a = Vec3::new(1.0, -2.0, -3.0);
assert_eq!(a.signum(), (1.0, -1.0, -1.0));
}
#[test]
fn rotate() {
use crate::Angle;
use approx::assert_abs_diff_eq;
let v = Vector3::<f32>::X;
let quat = Angle::from_degrees(180.0f32).to_rotation(Vector3::Z);
assert_abs_diff_eq!(quat * v, -v);
let v = Vector3::<f64>::X;
let quat = Angle::from_degrees(180.0f64).to_rotation(Vector3::Z);
assert_abs_diff_eq!(quat * v, -v);
}
#[test]
fn rotate2() {
let a = Vector2::<f32>::X;
let rotate_by = Angle::<f32>::FRAG_PI_2;
let b = Vector2::<f32>::from_angle(rotate_by);
let rotated = a.rotate(b);
assert_abs_diff_eq!(rotated, Vector2::<f32>::Y);
let x = glam::Vec2::X;
let rotate_by = glam::Vec2::from_angle(f32::FRAG_PI_2);
let y = x.rotate(rotate_by);
assert_abs_diff_eq!(rotated.to_raw(), y);
}
#[test]
fn matrix_mul_custom_unit() {
use crate::{vec3, Matrix3};
let mat = Matrix3::<f32>::IDENTITY;
let a: Vector3<F32> = vec3!(20.0, 30.0, 1.0);
let b: Vector3<F32> = mat * a;
assert_eq!(b, (20.0, 30.0, 1.0));
}
}
#[cfg(all(test, feature = "serde"))]
mod serde_tests {
use super::*;
#[test]
fn serde_vector() {
let vec = Vector4::<f32>::new(10.0, 20.0, 30.0, 40.0);
let serialized = serde_json::to_string(&vec).unwrap();
assert_eq!(serialized, r#"{"x":10.0,"y":20.0,"z":30.0,"w":40.0}"#);
let deserialized: Vector4<f32> = serde_json::from_str(&serialized).unwrap();
assert_eq!(vec, deserialized);
}
}