use crate::nums::*;
use crate::{BVec4x4, Vec4x4};
use crate::UnitVec4;
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::ops::*;
use auto_ops_det::{impl_op_ex, impl_op_ex_commutative};
use core::ops;
union VecUnionCast {
v: Vec4x4,
uv: UnitVec4x4,
}
impl Vec4x4 {
#[inline]
pub fn as_unit_vec4x4_unchecked(self) -> UnitVec4x4 {
unsafe { VecUnionCast { v: self }.uv }
}
}
impl UnitVec4x4 {
#[inline]
pub fn as_vec4x4(self) -> Vec4x4 {
unsafe { VecUnionCast { uv: self }.v }
}
}
#[derive(Clone, Copy, PartialEq)]
#[cfg_attr(feature = "cuda", repr(align(16)))]
#[repr(C)]
pub struct UnitVec4x4 {
pub x: f32x4,
pub y: f32x4,
pub z: f32x4,
pub w: f32x4,
}
impl UnitVec4x4 {
pub const X: Self = Self::new_unchecked(f32x4::ONE, f32x4::ZERO, f32x4::ZERO, f32x4::ZERO);
pub const Y: Self = Self::new_unchecked(f32x4::ZERO, f32x4::ONE, f32x4::ZERO, f32x4::ZERO);
pub const Z: Self = Self::new_unchecked(f32x4::ZERO, f32x4::ZERO, f32x4::ONE, f32x4::ZERO);
pub const W: Self = Self::new_unchecked(f32x4::ZERO, f32x4::ZERO, f32x4::ZERO, f32x4::ONE);
pub const NEG_X: Self =
Self::new_unchecked(f32x4::NEG_ONE, f32x4::ZERO, f32x4::ZERO, f32x4::ZERO);
pub const NEG_Y: Self =
Self::new_unchecked(f32x4::ZERO, f32x4::NEG_ONE, f32x4::ZERO, f32x4::ZERO);
pub const NEG_Z: Self =
Self::new_unchecked(f32x4::ZERO, f32x4::ZERO, f32x4::NEG_ONE, f32x4::ZERO);
pub const NEG_W: Self =
Self::new_unchecked(f32x4::ZERO, f32x4::ZERO, f32x4::ZERO, f32x4::NEG_ONE);
pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W];
#[inline]
pub const fn new_unchecked(x: f32x4, y: f32x4, z: f32x4, w: f32x4) -> Self {
Self { x, y, z, w }
}
#[inline]
pub fn new_normalized(x: f32x4, y: f32x4, z: f32x4, w: f32x4) -> Self {
Vec4x4::new(x, y, z, w)
.normalize()
.as_unit_vec4x4_unchecked()
}
#[inline]
pub fn select(mask: BVec4x4, if_true: Self, if_false: Self) -> Vec4x4 {
Vec4x4::select(mask, if_true.as_vec4x4(), if_false.as_vec4x4())
}
#[inline]
pub const fn from_array_unchecked(a: [f32x4; 4]) -> Self {
Self::new_unchecked(a[0], a[1], a[2], a[3])
}
#[inline]
pub const fn to_array(&self) -> [f32x4; 4] {
[self.x, self.y, self.z, self.w]
}
#[inline]
pub const fn from_slice_unchecked(slice: &[f32x4]) -> Self {
Self::new_unchecked(slice[0], slice[1], slice[2], slice[3])
}
#[inline]
pub fn write_to_slice(self, slice: &mut [f32x4]) {
slice[0] = self.x;
slice[1] = self.y;
slice[2] = self.z;
slice[3] = self.w;
}
#[inline]
pub(crate) fn dot(self, rhs: Self) -> f32x4 {
self.as_vec4x4().dot(rhs.as_vec4x4())
}
#[inline]
pub fn min_element(self) -> f32x4 {
self.as_vec4x4().min_element()
}
#[inline]
pub fn max_element(self) -> f32x4 {
self.as_vec4x4().max_element()
}
#[inline]
pub fn cmpeq(self, rhs: Self) -> BVec4x4 {
self.as_vec4x4().cmpeq(rhs.as_vec4x4())
}
#[inline]
pub fn cmpne(self, rhs: Self) -> BVec4x4 {
self.as_vec4x4().cmpne(rhs.as_vec4x4())
}
#[inline]
pub fn cmpge(self, rhs: Self) -> BVec4x4 {
self.as_vec4x4().cmpge(rhs.as_vec4x4())
}
#[inline]
pub fn cmpgt(self, rhs: Self) -> BVec4x4 {
self.as_vec4x4().cmpgt(rhs.as_vec4x4())
}
#[inline]
pub fn cmple(self, rhs: Self) -> BVec4x4 {
self.as_vec4x4().cmple(rhs.as_vec4x4())
}
#[inline]
pub fn cmplt(self, rhs: Self) -> BVec4x4 {
self.as_vec4x4().cmple(rhs.as_vec4x4())
}
#[inline]
pub fn abs(self) -> Self {
self.as_vec4x4().abs().as_unit_vec4x4_unchecked()
}
#[inline]
pub fn signum(self) -> Vec4x4 {
self.as_vec4x4().signum()
}
#[inline]
pub fn distance(self, rhs: Self) -> f32x4 {
self.as_vec4x4().distance(rhs.as_vec4x4())
}
#[inline]
pub fn distance_squared(self, rhs: Self) -> f32x4 {
self.as_vec4x4().distance_squared(rhs.as_vec4x4())
}
#[inline]
pub fn lane_select(cond: bool32x4, if_true: Self, if_false: Self) -> Self {
Self {
x: if_true.x.select(cond, if_false.x),
y: if_true.y.select(cond, if_false.y),
z: if_true.z.select(cond, if_false.z),
w: if_true.w.select(cond, if_false.w),
}
}
#[inline]
pub fn splat_soa(v: UnitVec4) -> Self {
Self {
x: f32x4::splat(v.x),
y: f32x4::splat(v.y),
z: f32x4::splat(v.z),
w: f32x4::splat(v.w),
}
}
#[inline]
pub fn extract_lane(&self, i: usize) -> UnitVec4 {
UnitVec4::new_unchecked(
self.x.extract(i),
self.y.extract(i),
self.z.extract(i),
self.w.extract(i),
)
}
#[inline]
pub fn replace_lane(&mut self, i: usize, v: UnitVec4) {
let mut nv = self.as_vec4x4();
nv.replace_lane(i, v.as_vec4());
*self = nv.as_unit_vec4x4_unchecked();
}
#[inline]
pub fn split_soa(self) -> [UnitVec4; 4] {
[
self.extract_lane(0),
self.extract_lane(1),
self.extract_lane(2),
self.extract_lane(3),
]
}
#[inline]
pub fn compose_soa(a: &[UnitVec4; 4]) -> UnitVec4x4 {
let mut v = Self::default();
v.replace_lane(0, a[0]);
v.replace_lane(1, a[1]);
v.replace_lane(2, a[2]);
v.replace_lane(3, a[3]);
v
}
#[must_use]
#[inline]
pub fn project_onto(self, rhs: Self) -> Vec4x4 {
rhs.as_vec4x4() * self.dot(rhs)
}
#[must_use]
#[inline]
pub fn reject_from(self, rhs: Self) -> Vec4x4 {
self.as_vec4x4() - self.project_onto(rhs)
}
#[doc(alias = "mix")]
#[inline]
pub fn lerp(self, rhs: Self, s: f32x4) -> Vec4x4 {
self.as_vec4x4().lerp(rhs.as_vec4x4(), s)
}
#[inline]
pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32x4) -> bool32x4 {
Vec4x4::abs_diff_eq(self.as_vec4x4(), rhs.as_vec4x4(), max_abs_diff)
}
#[inline]
pub fn mul_add(self, a: Self, b: Self) -> Vec4x4 {
self.as_vec4x4().mul_add(a.as_vec4x4(), b.as_vec4x4())
}
}
impl Default for UnitVec4x4 {
#[inline]
fn default() -> Self {
Self::X
}
}
impl Neg for UnitVec4x4 {
type Output = Self;
#[inline]
fn neg(self) -> Self {
self.as_vec4x4().neg().as_unit_vec4x4_unchecked()
}
}
impl_op_ex!(/ |a: &UnitVec4x4, b: &UnitVec4x4| -> Vec4x4 {
a.as_vec4x4() / b.as_vec4x4()
});
impl_op_ex!(/ |a: &UnitVec4x4, b: &f32x4| -> Vec4x4 {
a.as_vec4x4() / b
});
impl_op_ex!(/ |a: &f32x4, b: &UnitVec4x4| -> Vec4x4 {
a / b.as_vec4x4()
});
impl_op_ex_commutative!(/ |a: &UnitVec4x4, b: &Vec4x4| -> Vec4x4 {
a.as_vec4x4() / b
});
impl_op_ex!(*|a: &UnitVec4x4, b: &UnitVec4x4| -> Vec4x4 { a.as_vec4x4() * b.as_vec4x4() });
impl_op_ex!(*|a: &UnitVec4x4, b: &f32x4| -> Vec4x4 { a.as_vec4x4() * b });
impl_op_ex!(*|a: &f32x4, b: &UnitVec4x4| -> Vec4x4 { a * b.as_vec4x4() });
impl_op_ex_commutative!(*|a: &UnitVec4x4, b: &Vec4x4| -> Vec4x4 { a.as_vec4x4() * b });
impl_op_ex!(+ |a: &UnitVec4x4, b: &UnitVec4x4| -> Vec4x4 {
a.as_vec4x4() + b.as_vec4x4()
});
impl_op_ex!(+ |a: &UnitVec4x4, b: &f32x4| -> Vec4x4 {
a.as_vec4x4() + b
});
impl_op_ex!(+ |a: &f32x4, b: &UnitVec4x4| -> Vec4x4 {
a + b.as_vec4x4()
});
impl_op_ex_commutative!(+ |a: &UnitVec4x4, b: &Vec4x4| -> Vec4x4 {
a.as_vec4x4() + b
});
impl_op_ex!(-|a: &UnitVec4x4, b: &UnitVec4x4| -> Vec4x4 { a.as_vec4x4() - b.as_vec4x4() });
impl_op_ex!(-|a: &UnitVec4x4, b: &f32x4| -> Vec4x4 { a.as_vec4x4() - b });
impl_op_ex!(-|a: &f32x4, b: &UnitVec4x4| -> Vec4x4 { a - b.as_vec4x4() });
impl_op_ex_commutative!(-|a: &UnitVec4x4, b: &Vec4x4| -> Vec4x4 { a.as_vec4x4() - b });
impl_op_ex!(% |a: &UnitVec4x4, b: &UnitVec4x4| -> Vec4x4 {
a.as_vec4x4() % b.as_vec4x4()
});
impl_op_ex!(% |a: &UnitVec4x4, b: &f32x4| -> Vec4x4 {
a.as_vec4x4() % b
});
impl_op_ex!(% |a: &f32x4, b: &UnitVec4x4| -> Vec4x4 {
a % b.as_vec4x4()
});
impl_op_ex_commutative!(% |a: &UnitVec4x4, b: &Vec4x4| -> Vec4x4 {
a.as_vec4x4() % b
});
impl Index<usize> for UnitVec4x4 {
type Output = f32x4;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
3 => &self.w,
_ => panic!("index out of bounds"),
}
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for UnitVec4x4 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for UnitVec4x4 {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple(stringify!(UnitVec4x4))
.field(&self.x)
.field(&self.y)
.field(&self.z)
.field(&self.w)
.finish()
}
}
impl From<UnitVec4x4> for [f32x4; 4] {
#[inline]
fn from(v: UnitVec4x4) -> Self {
v.as_vec4x4().into()
}
}
impl From<UnitVec4x4> for (f32x4, f32x4, f32x4, f32x4) {
#[inline]
fn from(v: UnitVec4x4) -> Self {
v.as_vec4x4().into()
}
}
#[cfg(not(target_arch = "spirv"))]
impl AsRef<[f32x4; 4]> for UnitVec4x4 {
#[inline]
fn as_ref(&self) -> &[f32x4; 4] {
unsafe { &*(self as *const UnitVec4x4 as *const [f32x4; 4]) }
}
}