use crate::bool::simd_alias::BVec3A;
use crate::f32::simd_alias::Vec3A;
use crate::{UnitVec3, Vec3};
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::ops::*;
use core::arch::wasm32::*;
use crate::nums::*;
use auto_ops_det::{impl_op_ex, impl_op_ex_commutative};
use core::ops;
union VecUnionCast {
v: Vec3A,
uv: UnitVec3A,
}
impl Vec3A {
#[inline]
pub fn as_unit_vec3a_unchecked(self) -> UnitVec3A {
unsafe { VecUnionCast { v: self }.uv }
}
}
impl UnitVec3A {
#[inline]
pub fn as_vec3a(self) -> Vec3A {
unsafe { VecUnionCast { uv: self }.v }
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct UnitVec3A(pub(crate) v128);
impl UnitVec3A {
pub const X: Self = Self::new_unchecked(1.0_f32, 0.0_f32, 0.0_f32);
pub const Y: Self = Self::new_unchecked(0.0_f32, 1.0_f32, 0.0_f32);
pub const Z: Self = Self::new_unchecked(0.0_f32, 0.0_f32, 1.0_f32);
pub const NEG_X: Self = Self::new_unchecked(-1.0_f32, 0.0_f32, 0.0_f32);
pub const NEG_Y: Self = Self::new_unchecked(0.0_f32, -1.0_f32, 0.0_f32);
pub const NEG_Z: Self = Self::new_unchecked(0.0_f32, 0.0_f32, -1.0_f32);
pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
#[inline]
pub const fn new_unchecked(x: f32, y: f32, z: f32) -> Self {
Self(f32x4(x, y, z, z))
}
#[inline]
pub fn new_normalized(x: f32, y: f32, z: f32) -> Self {
Vec3A::new(x, y, z).normalize().as_unit_vec3a_unchecked()
}
#[inline]
pub fn select(mask: BVec3A, if_true: Self, if_false: Self) -> Vec3A {
Vec3A::select(mask, if_true.as_vec3a(), if_false.as_vec3a())
}
#[inline]
pub const fn from_array_unchecked(a: [f32; 3]) -> Self {
Self::new_unchecked(a[0], a[1], a[2])
}
#[inline]
pub const fn to_array(&self) -> [f32; 3] {
unsafe { *(self as *const UnitVec3A as *const [f32; 3]) }
}
#[inline]
pub const fn from_slice_unchecked(slice: &[f32]) -> Self {
Self::new_unchecked(slice[0], slice[1], slice[2])
}
#[inline]
pub fn write_to_slice(self, slice: &mut [f32]) {
slice[0] = self.x;
slice[1] = self.y;
slice[2] = self.z;
}
#[inline]
pub(crate) fn dot(self, rhs: Self) -> f32 {
self.as_vec3a().dot(rhs.as_vec3a())
}
#[inline]
pub(crate) fn cross(self, rhs: Self) -> Vec3A {
self.as_vec3a().cross(rhs.as_vec3a())
}
#[inline]
pub fn min_element(self) -> f32 {
self.as_vec3a().min_element()
}
#[inline]
pub fn max_element(self) -> f32 {
self.as_vec3a().max_element()
}
#[inline]
pub fn cmpeq(self, rhs: Self) -> BVec3A {
self.as_vec3a().cmpeq(rhs.as_vec3a())
}
#[inline]
pub fn cmpne(self, rhs: Self) -> BVec3A {
self.as_vec3a().cmpne(rhs.as_vec3a())
}
#[inline]
pub fn cmpge(self, rhs: Self) -> BVec3A {
self.as_vec3a().cmpge(rhs.as_vec3a())
}
#[inline]
pub fn cmpgt(self, rhs: Self) -> BVec3A {
self.as_vec3a().cmpgt(rhs.as_vec3a())
}
#[inline]
pub fn cmple(self, rhs: Self) -> BVec3A {
self.as_vec3a().cmple(rhs.as_vec3a())
}
#[inline]
pub fn cmplt(self, rhs: Self) -> BVec3A {
self.as_vec3a().cmple(rhs.as_vec3a())
}
#[inline]
pub fn abs(self) -> Self {
self.as_vec3a().abs().as_unit_vec3a_unchecked()
}
#[inline]
pub fn signum(self) -> Vec3A {
self.as_vec3a().signum()
}
#[inline]
pub fn distance(self, rhs: Self) -> f32 {
self.as_vec3a().distance(rhs.as_vec3a())
}
#[inline]
pub fn distance_squared(self, rhs: Self) -> f32 {
self.as_vec3a().distance_squared(rhs.as_vec3a())
}
#[must_use]
#[inline]
pub fn project_onto(self, rhs: Self) -> Vec3A {
rhs.as_vec3a() * self.dot(rhs)
}
#[must_use]
#[inline]
pub fn reject_from(self, rhs: Self) -> Vec3A {
self.as_vec3a() - self.project_onto(rhs)
}
#[doc(alias = "mix")]
#[inline]
pub fn lerp(self, rhs: Self, s: f32) -> Vec3A {
self.as_vec3a().lerp(rhs.as_vec3a(), s)
}
#[inline]
pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
Vec3A::abs_diff_eq(self.as_vec3a(), rhs.as_vec3a(), max_abs_diff)
}
#[inline]
pub fn mul_add(self, a: Self, b: Self) -> Vec3A {
self.as_vec3a().mul_add(a.as_vec3a(), b.as_vec3a())
}
#[inline]
pub fn angle_between(self, rhs: Self) -> f32 {
use crate::FloatEx;
self.dot(rhs).acos_approx()
}
#[inline]
pub fn any_orthogonal_vector(&self) -> Self {
let sign = 1.0_f32.copysignf(self.z);
let a = -1.0_f32 / (sign + self.z);
let b = self.x * self.y * a;
Self::new_unchecked(b, sign + self.y * self.y * a, -self.y)
}
#[inline]
pub fn any_orthogonal_pair(&self) -> (Self, Self) {
let sign = 1.0_f32.copysignf(self.z);
let a = -1.0_f32 / (sign + self.z);
let b = self.x * self.y * a;
(
Self::new_unchecked(
1.0_f32 + sign * self.x * self.x * a,
sign * b,
-sign * self.x,
),
Self::new_unchecked(b, sign + self.y * self.y * a, -self.y),
)
}
}
impl Default for UnitVec3A {
#[inline]
fn default() -> Self {
Self::X
}
}
impl PartialEq for UnitVec3A {
#[inline]
fn eq(&self, rhs: &Self) -> bool {
self.cmpeq(*rhs).all()
}
}
impl Neg for UnitVec3A {
type Output = Self;
#[inline]
fn neg(self) -> Self {
self.as_vec3a().neg().as_unit_vec3a_unchecked()
}
}
impl_op_ex!(/ |a: &UnitVec3A, b: &UnitVec3A| -> Vec3A {
a.as_vec3a() / b.as_vec3a()
});
impl_op_ex!(/ |a: &UnitVec3A, b: &f32| -> Vec3A {
a.as_vec3a() / b
});
impl_op_ex!(/ |a: &f32, b: &UnitVec3A| -> Vec3A {
a / b.as_vec3a()
});
impl_op_ex_commutative!(/ |a: &UnitVec3A, b: &Vec3A| -> Vec3A {
a.as_vec3a() / b
});
impl_op_ex!(*|a: &UnitVec3A, b: &UnitVec3A| -> Vec3A { a.as_vec3a() * b.as_vec3a() });
impl_op_ex!(*|a: &UnitVec3A, b: &f32| -> Vec3A { a.as_vec3a() * b });
impl_op_ex!(*|a: &f32, b: &UnitVec3A| -> Vec3A { a * b.as_vec3a() });
impl_op_ex_commutative!(*|a: &UnitVec3A, b: &Vec3A| -> Vec3A { a.as_vec3a() * b });
impl_op_ex!(+ |a: &UnitVec3A, b: &UnitVec3A| -> Vec3A {
a.as_vec3a() + b.as_vec3a()
});
impl_op_ex!(+ |a: &UnitVec3A, b: &f32| -> Vec3A {
a.as_vec3a() + b
});
impl_op_ex!(+ |a: &f32, b: &UnitVec3A| -> Vec3A {
a + b.as_vec3a()
});
impl_op_ex_commutative!(+ |a: &UnitVec3A, b: &Vec3A| -> Vec3A {
a.as_vec3a() + b
});
impl_op_ex!(-|a: &UnitVec3A, b: &UnitVec3A| -> Vec3A { a.as_vec3a() - b.as_vec3a() });
impl_op_ex!(-|a: &UnitVec3A, b: &f32| -> Vec3A { a.as_vec3a() - b });
impl_op_ex!(-|a: &f32, b: &UnitVec3A| -> Vec3A { a - b.as_vec3a() });
impl_op_ex_commutative!(-|a: &UnitVec3A, b: &Vec3A| -> Vec3A { a.as_vec3a() - b });
impl_op_ex!(% |a: &UnitVec3A, b: &UnitVec3A| -> Vec3A {
a.as_vec3a() % b.as_vec3a()
});
impl_op_ex!(% |a: &UnitVec3A, b: &f32| -> Vec3A {
a.as_vec3a() % b
});
impl_op_ex!(% |a: &f32, b: &UnitVec3A| -> Vec3A {
a % b.as_vec3a()
});
impl_op_ex_commutative!(% |a: &UnitVec3A, b: &Vec3A| -> Vec3A {
a.as_vec3a() % b
});
impl Index<usize> for UnitVec3A {
type Output = f32;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!("index out of bounds"),
}
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for UnitVec3A {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for UnitVec3A {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple(stringify!(UnitVec3A))
.field(&self.x)
.field(&self.y)
.field(&self.z)
.finish()
}
}
impl From<UnitVec3A> for v128 {
#[inline]
fn from(t: UnitVec3A) -> Self {
t.0
}
}
impl From<UnitVec3A> for [f32; 3] {
#[inline]
fn from(v: UnitVec3A) -> Self {
v.as_vec3a().into()
}
}
impl From<UnitVec3A> for (f32, f32, f32) {
#[inline]
fn from(v: UnitVec3A) -> Self {
v.as_vec3a().into()
}
}
impl From<UnitVec3> for UnitVec3A {
#[inline]
fn from(v: UnitVec3) -> Self {
Self::new_unchecked(v.x, v.y, v.z)
}
}
impl From<UnitVec3A> for UnitVec3 {
#[inline]
fn from(v: UnitVec3A) -> Self {
Vec3::from(v.as_vec3a()).as_unit_vec3_unchecked()
}
}
impl Deref for UnitVec3A {
type Target = crate::deref::Vec3<f32>;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self).cast() }
}
}
#[cfg(not(target_arch = "spirv"))]
impl AsRef<[f32; 3]> for UnitVec3A {
#[inline]
fn as_ref(&self) -> &[f32; 3] {
unsafe { &*(self as *const UnitVec3A as *const [f32; 3]) }
}
}