blob: 98ffa380ece6bbb821bfc143dddd348534c59559 [file] [log] [blame]
use crate::core::traits::vector::*;
use crate::{BVec2, DVec3, IVec3, UVec3, Vec3, XY};
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::iter::{Product, Sum};
use core::{f32, ops::*};
#[cfg(not(feature = "std"))]
use num_traits::Float;
macro_rules! impl_vec2_common_methods {
($t:ty, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => {
/// All zeroes.
pub const ZERO: Self = Self($inner::ZERO);
/// All ones.
pub const ONE: Self = Self($inner::ONE);
/// `[1, 0]`: a unit-length vector pointing along the positive X axis.
pub const X: Self = Self($inner::X);
/// `[0, 1]`: a unit-length vector pointing along the positive Y axis.
pub const Y: Self = Self($inner::Y);
/// The unit axes.
pub const AXES: [Self; 2] = [Self::X, Self::Y];
/// Creates a new vector.
#[inline(always)]
pub fn new(x: $t, y: $t) -> $vec2 {
Self(Vector2::new(x, y))
}
/// Creates a 3D vector from `self` and the given `z` value.
#[inline(always)]
pub fn extend(self, z: $t) -> $vec3 {
$vec3::new(self.x, self.y, z)
}
/// `[x, y]`
#[inline(always)]
pub fn to_array(&self) -> [$t; 2] {
[self.x, self.y]
}
impl_vecn_common_methods!($t, $vec2, $mask, $inner, Vector2);
};
}
macro_rules! impl_vec2_signed_methods {
($t:ty, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => {
impl_vec2_common_methods!($t, $vec2, $vec3, $mask, $inner);
impl_vecn_signed_methods!($t, $vec2, $mask, $inner, SignedVector2);
/// Returns a vector that is equal to `self` rotated by 90 degrees.
#[inline(always)]
pub fn perp(self) -> Self {
Self(self.0.perp())
}
/// The perpendicular dot product of `self` and `other`.
/// Also known as the wedge product, 2d cross product, and determinant.
#[doc(alias = "wedge")]
#[doc(alias = "cross")]
#[doc(alias = "determinant")]
#[inline(always)]
pub fn perp_dot(self, other: $vec2) -> $t {
self.0.perp_dot(other.0)
}
};
}
macro_rules! impl_vec2_float_methods {
($t:ty, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => {
impl_vec2_signed_methods!($t, $vec2, $vec3, $mask, $inner);
impl_vecn_float_methods!($t, $vec2, $mask, $inner, FloatVector2);
/// Returns the angle (in radians) between `self` and `other`.
///
/// The input vectors do not need to be unit length however they must be non-zero.
#[inline(always)]
pub fn angle_between(self, other: Self) -> $t {
self.0.angle_between(other.0)
}
};
}
macro_rules! impl_vec2_common_traits {
($t:ty, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => {
/// Creates a 2-dimensional vector.
#[inline(always)]
pub fn $new(x: $t, y: $t) -> $vec2 {
$vec2::new(x, y)
}
impl Index<usize> for $vec2 {
type Output = $t;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
_ => panic!("index out of bounds"),
}
}
}
impl IndexMut<usize> for $vec2 {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
_ => panic!("index out of bounds"),
}
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for $vec2 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}, {}]", self.x, self.y)
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for $vec2 {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple(stringify!($vec2))
.field(&self.x)
.field(&self.y)
.finish()
}
}
impl From<($t, $t)> for $vec2 {
#[inline(always)]
fn from(t: ($t, $t)) -> Self {
Self($inner::from_tuple(t))
}
}
impl From<$vec2> for ($t, $t) {
#[inline(always)]
fn from(v: $vec2) -> Self {
v.0.into_tuple()
}
}
impl Deref for $vec2 {
type Target = XY<$t>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.0.as_ref_xy()
}
}
impl DerefMut for $vec2 {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut_xy()
}
}
impl_vecn_common_traits!($t, 2, $vec2, $inner, Vector2);
};
}
macro_rules! impl_vec2_unsigned_traits {
($t:ty, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => {
impl_vec2_common_traits!($t, $new, $vec2, $vec3, $mask, $inner);
};
}
macro_rules! impl_vec2_signed_traits {
($t:ty, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $inner:ident) => {
impl_vec2_common_traits!($t, $new, $vec2, $vec3, $mask, $inner);
impl_vecn_signed_traits!($t, 2, $vec2, $inner, SignedVector2);
};
}
type XYF32 = XY<f32>;
/// A 2-dimensional vector.
#[derive(Clone, Copy)]
#[cfg_attr(feature = "cuda", repr(C, align(8)))]
#[cfg_attr(not(feature = "cuda"), repr(transparent))]
pub struct Vec2(pub(crate) XYF32);
impl Vec2 {
impl_vec2_float_methods!(f32, Vec2, Vec3, BVec2, XYF32);
impl_as_dvec2!();
impl_as_ivec2!();
impl_as_uvec2!();
}
impl_vec2_signed_traits!(f32, vec2, Vec2, Vec3, BVec2, XYF32);
type XYF64 = XY<f64>;
/// A 2-dimensional vector.
#[derive(Clone, Copy)]
#[cfg_attr(feature = "cuda", repr(C, align(16)))]
#[cfg_attr(not(feature = "cuda"), repr(transparent))]
pub struct DVec2(pub(crate) XYF64);
impl DVec2 {
impl_vec2_float_methods!(f64, DVec2, DVec3, BVec2, XYF64);
impl_as_vec2!();
impl_as_ivec2!();
impl_as_uvec2!();
}
impl_vec2_signed_traits!(f64, dvec2, DVec2, DVec3, BVec2, XYF64);
type XYI32 = XY<i32>;
/// A 2-dimensional vector.
#[derive(Clone, Copy)]
#[cfg_attr(feature = "cuda", repr(C, align(8)))]
#[cfg_attr(not(feature = "cuda"), repr(transparent))]
pub struct IVec2(pub(crate) XYI32);
impl IVec2 {
impl_vec2_signed_methods!(i32, IVec2, IVec3, BVec2, XYI32);
impl_as_vec2!();
impl_as_dvec2!();
impl_as_uvec2!();
}
impl_vec2_signed_traits!(i32, ivec2, IVec2, IVec3, BVec2, XYI32);
impl_vecn_eq_hash_traits!(i32, 2, IVec2);
impl_vecn_scalar_shift_op_traits!(IVec2, i8, XYI32);
impl_vecn_scalar_shift_op_traits!(IVec2, i16, XYI32);
impl_vecn_scalar_shift_op_traits!(IVec2, i32, XYI32);
impl_vecn_scalar_shift_op_traits!(IVec2, u8, XYI32);
impl_vecn_scalar_shift_op_traits!(IVec2, u16, XYI32);
impl_vecn_scalar_shift_op_traits!(IVec2, u32, XYI32);
impl_vecn_shift_op_traits!(IVec2, IVec2, XYI32);
impl_vecn_shift_op_traits!(IVec2, UVec2, XYI32);
impl_vecn_scalar_bit_op_traits!(IVec2, i32, XYI32);
impl_vecn_bit_op_traits!(IVec2, XYI32);
type XYU32 = XY<u32>;
/// A 2-dimensional vector.
#[derive(Clone, Copy)]
#[cfg_attr(feature = "cuda", repr(C, align(8)))]
#[cfg_attr(not(feature = "cuda"), repr(transparent))]
pub struct UVec2(pub(crate) XYU32);
impl UVec2 {
impl_vec2_common_methods!(u32, UVec2, UVec3, BVec2, XYU32);
impl_as_vec2!();
impl_as_dvec2!();
impl_as_ivec2!();
}
impl_vec2_unsigned_traits!(u32, uvec2, UVec2, UVec3, BVec2, XYU32);
impl_vecn_eq_hash_traits!(u32, 2, UVec2);
impl_vecn_scalar_shift_op_traits!(UVec2, i8, XYU32);
impl_vecn_scalar_shift_op_traits!(UVec2, i16, XYU32);
impl_vecn_scalar_shift_op_traits!(UVec2, i32, XYU32);
impl_vecn_scalar_shift_op_traits!(UVec2, u8, XYU32);
impl_vecn_scalar_shift_op_traits!(UVec2, u16, XYU32);
impl_vecn_scalar_shift_op_traits!(UVec2, u32, XYU32);
impl_vecn_shift_op_traits!(UVec2, IVec2, XYU32);
impl_vecn_shift_op_traits!(UVec2, UVec2, XYU32);
impl_vecn_scalar_bit_op_traits!(UVec2, u32, XYU32);
impl_vecn_bit_op_traits!(UVec2, XYU32);
mod const_test_vec2 {
#[cfg(not(feature = "cuda"))]
const_assert_eq!(
core::mem::align_of::<f32>(),
core::mem::align_of::<super::Vec2>()
);
#[cfg(feature = "cuda")]
const_assert_eq!(8, core::mem::align_of::<super::Vec2>());
const_assert_eq!(8, core::mem::size_of::<super::Vec2>());
}
mod const_test_dvec2 {
#[cfg(not(feature = "cuda"))]
const_assert_eq!(
core::mem::align_of::<f64>(),
core::mem::align_of::<super::DVec2>()
);
#[cfg(feature = "cuda")]
const_assert_eq!(16, core::mem::align_of::<super::DVec2>());
const_assert_eq!(16, core::mem::size_of::<super::DVec2>());
}
mod const_test_ivec2 {
#[cfg(not(feature = "cuda"))]
const_assert_eq!(
core::mem::align_of::<i32>(),
core::mem::align_of::<super::IVec2>()
);
#[cfg(feature = "cuda")]
const_assert_eq!(8, core::mem::align_of::<super::IVec2>());
const_assert_eq!(8, core::mem::size_of::<super::IVec2>());
}
mod const_test_uvec2 {
#[cfg(not(feature = "cuda"))]
const_assert_eq!(
core::mem::align_of::<u32>(),
core::mem::align_of::<super::UVec2>()
);
#[cfg(feature = "cuda")]
const_assert_eq!(8, core::mem::align_of::<super::UVec2>());
const_assert_eq!(8, core::mem::size_of::<super::UVec2>());
}