use crate::core::traits::vector::*;
#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
use crate::BVec3A;
use crate::{BVec3, DVec2, DVec4, IVec2, IVec4, UVec2, UVec4, Vec2, Vec4, XYZ};
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::{cmp::Ordering, f32, ops::*};
#[cfg(not(feature = "std"))]
use num_traits::Float;
#[cfg(all(
target_arch = "x86",
target_feature = "sse2",
not(feature = "scalar-math")
))]
use core::arch::x86::*;
#[cfg(all(
target_arch = "x86_64",
target_feature = "sse2",
not(feature = "scalar-math")
))]
use core::arch::x86_64::*;
#[cfg(feature = "std")]
use std::iter::{Product, Sum};
macro_rules! impl_vec3_common_methods {
($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => {
pub const ZERO: Self = Self(VectorConst::ZERO);
pub const ONE: Self = Self(VectorConst::ONE);
pub const X: Self = Self(Vector3Const::X);
pub const Y: Self = Self(Vector3Const::Y);
pub const Z: Self = Self(Vector3Const::Z);
#[inline(always)]
pub fn new(x: $t, y: $t, z: $t) -> Self {
Self(Vector3::new(x, y, z))
}
#[deprecated = "Use Vec3::X instead"]
#[inline(always)]
pub const fn unit_x() -> Self {
Self(Vector3Const::X)
}
#[inline(always)]
#[deprecated = "Use Vec3::Y instead"]
pub const fn unit_y() -> Self {
Self(Vector3Const::Y)
}
#[inline(always)]
#[deprecated = "Use Vec3::Z instead"]
pub const fn unit_z() -> Self {
Self(Vector3Const::Z)
}
#[inline(always)]
pub fn extend(self, w: $t) -> $vec4 {
$vec4(Vector4::new(self.x, self.y, self.z, w))
}
#[inline(always)]
pub fn truncate(self) -> $vec2 {
$vec2(Vector3::into_xy(self.0))
}
#[inline(always)]
#[allow(dead_code)]
pub(crate) fn dot_as_vec3(self, other: Self) -> Self {
Self(Vector3::dot_into_vec(self.0, other.0))
}
#[inline(always)]
pub fn cross(self, other: Self) -> Self {
Self(self.0.cross(other.0))
}
impl_vecn_common_methods!($t, $vec3, $mask, $inner, Vector3);
};
}
macro_rules! impl_vec3_common_traits {
($t:ty, $new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => {
#[inline(always)]
pub fn $new(x: $t, y: $t, z: $t) -> $vec3 {
$vec3::new(x, y, z)
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for $vec3 {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let a = self.as_ref();
fmt.debug_tuple(stringify!($vec3))
.field(&a[0])
.field(&a[1])
.field(&a[2])
.finish()
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for $vec3 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
}
}
impl From<($vec2, $t)> for $vec3 {
#[inline(always)]
fn from((v, z): ($vec2, $t)) -> Self {
Self::new(v.x, v.y, z)
}
}
impl From<($t, $t, $t)> for $vec3 {
#[inline(always)]
fn from(t: ($t, $t, $t)) -> Self {
Self(Vector3::from_tuple(t))
}
}
impl From<$vec3> for ($t, $t, $t) {
#[inline(always)]
fn from(v: $vec3) -> Self {
v.into_tuple()
}
}
impl From<$vec3> for $vec2 {
#[inline(always)]
fn from(v: $vec3) -> Self {
Self(v.into_xy())
}
}
impl Deref for $vec3 {
type Target = XYZ<$t>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.0.as_ref_xyz()
}
}
impl DerefMut for $vec3 {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut_xyz()
}
}
impl_vecn_common_traits!($t, 3, $vec3, $inner, Vector3);
};
}
macro_rules! impl_vec3_signed_methods {
($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => {
impl_vec3_common_methods!($t, $vec2, $vec3, $vec4, $mask, $inner);
impl_vecn_signed_methods!($t, $vec3, $mask, $inner, SignedVector3);
};
}
macro_rules! impl_vec3_float_methods {
($t:ty, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => {
impl_vec3_signed_methods!($t, $vec2, $vec3, $vec4, $mask, $inner);
impl_vecn_float_methods!($t, $vec3, $mask, $inner, FloatVector3);
#[inline(always)]
pub fn angle_between(self, other: Self) -> $t {
self.0.angle_between(other.0)
}
#[inline]
#[cfg(feature = "std")]
pub fn any_orthogonal_vector(&self) -> Self {
if self.x.abs() > self.y.abs() {
Self::new(-self.z, 0.0, self.x)
} else {
Self::new(0.0, self.z, -self.y)
}
}
#[inline]
#[cfg(feature = "std")]
pub fn any_orthonormal_vector(&self) -> Self {
glam_assert!(self.is_normalized());
let sign = (1.0 as $t).copysign(self.z);
let a = -1.0 / (sign + self.z);
let b = self.x * self.y * a;
Self::new(b, sign + self.y * self.y * a, -self.y)
}
#[inline]
#[cfg(feature = "std")]
pub fn any_orthonormal_pair(&self) -> (Self, Self) {
glam_assert!(self.is_normalized());
let sign = (1.0 as $t).copysign(self.z);
let a = -1.0 / (sign + self.z);
let b = self.x * self.y * a;
(
Self::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x),
Self::new(b, sign + self.y * self.y * a, -self.y),
)
}
};
}
macro_rules! impl_vec3_float_traits {
($t:ty, $new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => {
impl_vec3_common_traits!($t, $new, $vec2, $vec3, $vec4, $mask, $inner);
impl_vecn_signed_traits!($t, 3, $vec3, $inner, SignedVector3);
};
}
macro_rules! impl_f32_vec3 {
($new:ident, $vec2:ident, $vec3:ident, $vec4:ident, $mask:ident, $inner:ident) => {
impl $vec3 {
impl_vec3_float_methods!(f32, $vec2, $vec3, $vec4, $mask, $inner);
impl_vecn_as_f64!(DVec3, x, y, z);
impl_vecn_as_i32!(IVec3, x, y, z);
impl_vecn_as_u32!(UVec3, x, y, z);
}
impl_vec3_float_traits!(f32, $new, $vec2, $vec3, $vec4, $mask, $inner);
};
}
type XYZF32 = XYZ<f32>;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Vec3(pub(crate) XYZF32);
impl_f32_vec3!(vec3, Vec2, Vec3, Vec4, BVec3, XYZF32);
#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Vec3A(pub(crate) __m128);
#[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))]
#[derive(Clone, Copy)]
#[cfg_attr(not(target_arch = "spirv"), repr(align(16), C))]
#[cfg_attr(target_arch = "spirv", repr(transparent))]
pub struct Vec3A(pub(crate) XYZF32);
#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
impl_f32_vec3!(vec3a, Vec2, Vec3A, Vec4, BVec3A, __m128);
#[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))]
impl_f32_vec3!(vec3a, Vec2, Vec3A, Vec4, BVec3, XYZF32);
impl From<Vec3> for Vec3A {
#[inline(always)]
fn from(v: Vec3) -> Self {
#[allow(clippy::useless_conversion)]
Self(v.0.into())
}
}
impl From<Vec3A> for Vec3 {
#[inline(always)]
fn from(v: Vec3A) -> Self {
#[allow(clippy::useless_conversion)]
Self(v.0.into())
}
}
type XYZF64 = XYZ<f64>;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct DVec3(pub(crate) XYZF64);
impl DVec3 {
impl_vec3_float_methods!(f64, DVec2, DVec3, DVec4, BVec3, XYZF64);
impl_vecn_as_f32!(Vec3, x, y, z);
impl_vecn_as_i32!(IVec3, x, y, z);
impl_vecn_as_u32!(UVec3, x, y, z);
}
impl_vec3_float_traits!(f64, dvec3, DVec2, DVec3, DVec4, BVec3, XYZF64);
type XYZI32 = XYZ<i32>;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct IVec3(pub(crate) XYZI32);
impl IVec3 {
impl_vec3_common_methods!(i32, IVec2, IVec3, IVec4, BVec3, XYZI32);
impl_vecn_signed_methods!(i32, IVec3, BVec3, XYZI32, SignedVector3);
impl_vecn_as_f32!(Vec3, x, y, z);
impl_vecn_as_f64!(DVec3, x, y, z);
impl_vecn_as_u32!(UVec3, x, y, z);
}
impl_vec3_common_traits!(i32, ivec3, IVec2, IVec3, IVec4, BVec3, XYZI32);
impl_vecn_signed_traits!(i32, 3, IVec3, XYZI32, SignedVector3);
impl_vecn_eq_hash_traits!(i32, 3, IVec3);
type XYZU32 = XYZ<u32>;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct UVec3(pub(crate) XYZU32);
impl UVec3 {
impl_vec3_common_methods!(u32, UVec2, UVec3, UVec4, BVec3, XYZU32);
impl_vecn_as_f32!(Vec3, x, y, z);
impl_vecn_as_f64!(DVec3, x, y, z);
impl_vecn_as_i32!(IVec3, x, y, z);
}
impl_vec3_common_traits!(u32, uvec3, UVec2, UVec3, UVec4, BVec3, XYZU32);
impl_vecn_eq_hash_traits!(u32, 3, UVec3);
#[test]
fn test_vec3_private() {
assert_eq!(
vec3a(1.0, 1.0, 1.0).mul_add(vec3a(0.5, 2.0, -4.0), vec3a(-1.0, -1.0, -1.0)),
vec3a(-0.5, 1.0, -5.0)
);
}