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::{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);
pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
#[inline(always)]
pub fn new(x: $t, y: $t, z: $t) -> Self {
Self(Vector3::new(x, y, 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))
}
#[inline(always)]
pub fn to_array(&self) -> [$t; 3] {
[self.x, self.y, self.z]
}
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, $inner:ident) => {
#[inline(always)]
pub fn $new(x: $t, y: $t, z: $t) -> $vec3 {
$vec3::new(x, y, z)
}
impl Index<usize> for $vec3 {
type Output = $t;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!("index out of bounds"),
}
}
}
impl IndexMut<usize> for $vec3 {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
_ => panic!("index out of bounds"),
}
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for $vec3 {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_tuple(stringify!($vec3))
.field(&self.x)
.field(&self.y)
.field(&self.z)
.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, $inner:ident) => {
impl_vec3_common_traits!($t, $new, $vec2, $vec3, $vec4, $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, $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")))]
type XYZF32A = __m128;
#[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))]
type XYZF32A = crate::core::storage::XYZF32A16;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Vec3A(pub(crate) XYZF32A);
#[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
impl_f32_vec3!(vec3a, Vec2, Vec3A, Vec4, BVec3A, XYZF32A);
#[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))]
impl_f32_vec3!(vec3a, Vec2, Vec3A, Vec4, BVec3, XYZF32A);
impl From<Vec3> for Vec3A {
#[inline(always)]
fn from(v: Vec3) -> Self {
Self(v.0.into())
}
}
impl From<Vec3A> for Vec3 {
#[inline(always)]
fn from(v: Vec3A) -> Self {
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, 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, 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, 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)
);
}
mod const_test_vec3 {
const_assert_eq!(
core::mem::align_of::<f32>(),
core::mem::align_of::<super::Vec3>()
);
const_assert_eq!(12, core::mem::size_of::<super::Vec3>());
}
mod const_test_vec3a {
const_assert_eq!(16, core::mem::align_of::<super::Vec3A>());
const_assert_eq!(16, core::mem::size_of::<super::Vec3A>());
}
mod const_test_dvec3 {
const_assert_eq!(
core::mem::align_of::<f64>(),
core::mem::align_of::<super::DVec3>()
);
const_assert_eq!(24, core::mem::size_of::<super::DVec3>());
}
mod const_test_ivec3 {
const_assert_eq!(
core::mem::align_of::<i32>(),
core::mem::align_of::<super::IVec3>()
);
const_assert_eq!(12, core::mem::size_of::<super::IVec3>());
}
mod const_test_uvec3 {
const_assert_eq!(
core::mem::align_of::<u32>(),
core::mem::align_of::<super::UVec3>()
);
const_assert_eq!(12, core::mem::size_of::<super::UVec3>());
}