use super::*;
#[derive(Clone, Copy, Default)]
#[repr(align(16), C)]
pub struct Vec4 {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) sse: m128,
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
pub(crate) arr: [f32; 4],
}
unsafe impl Zeroable for Vec4 {}
unsafe impl Pod for Vec4 {}
impl core::cmp::PartialEq for Vec4 {
#[inline]
fn eq(&self, rhs: &Self) -> bool {
if_sse! {{
self.sse.cmp_eq(rhs.sse).move_mask() == 0b1111
} else {
let eq0 = self.arr[0] == rhs.arr[0];
let eq1 = self.arr[1] == rhs.arr[1];
let eq2 = self.arr[2] == rhs.arr[2];
let eq3 = self.arr[3] == rhs.arr[3];
eq0 & eq1 & eq2 & eq3
}}
}
}
impl core::fmt::Debug for Vec4 {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let [x, y, z, w]: [f32; 4] = cast(*self);
f.write_str("Vec4 { x: ")?;
core::fmt::Debug::fmt(&x, f)?;
f.write_str(", y: ")?;
core::fmt::Debug::fmt(&y, f)?;
f.write_str(", z: ")?;
core::fmt::Debug::fmt(&z, f)?;
f.write_str(", w: ")?;
core::fmt::Debug::fmt(&w, f)?;
f.write_str(" }")
}
}
impl core::fmt::Display for Vec4 {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let [x, y, z, w]: [f32; 4] = cast(*self);
f.write_str("(")?;
core::fmt::Display::fmt(&x, f)?;
f.write_str(", ")?;
core::fmt::Display::fmt(&y, f)?;
f.write_str(", ")?;
core::fmt::Display::fmt(&z, f)?;
f.write_str(", ")?;
core::fmt::Display::fmt(&w, f)?;
f.write_str(")")
}
}
impl core::fmt::LowerExp for Vec4 {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let [x, y, z, w]: [f32; 4] = cast(*self);
f.write_str("(")?;
core::fmt::LowerExp::fmt(&x, f)?;
f.write_str(", ")?;
core::fmt::LowerExp::fmt(&y, f)?;
f.write_str(", ")?;
core::fmt::LowerExp::fmt(&z, f)?;
f.write_str(", ")?;
core::fmt::LowerExp::fmt(&w, f)?;
f.write_str(")")
}
}
impl core::fmt::UpperExp for Vec4 {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let [x, y, z, w]: [f32; 4] = cast(*self);
f.write_str("(")?;
core::fmt::UpperExp::fmt(&x, f)?;
f.write_str(", ")?;
core::fmt::UpperExp::fmt(&y, f)?;
f.write_str(", ")?;
core::fmt::UpperExp::fmt(&z, f)?;
f.write_str(", ")?;
core::fmt::UpperExp::fmt(&w, f)?;
f.write_str(")")
}
}
impl Index<usize> for Vec4 {
type Output = f32;
#[inline(always)]
fn index(&self, index: usize) -> &f32 {
let arr_ref: &[f32; 4] = cast_ref(self);
match index {
0 => &arr_ref[0],
1 => &arr_ref[1],
2 => &arr_ref[2],
3 => &arr_ref[3],
otherwise => panic!("Vec4 index out of bounds: {}", otherwise),
}
}
}
impl IndexMut<usize> for Vec4 {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut f32 {
let arr_mut: &mut [f32; 4] = cast_mut(self);
match index {
0 => &mut arr_mut[0],
1 => &mut arr_mut[1],
2 => &mut arr_mut[2],
3 => &mut arr_mut[3],
otherwise => panic!("Vec4 index out of bounds: {}", otherwise),
}
}
}
impl AsRef<[f32; 4]> for Vec4 {
#[inline(always)]
fn as_ref(&self) -> &[f32; 4] {
cast_ref(self)
}
}
impl AsMut<[f32; 4]> for Vec4 {
#[inline(always)]
fn as_mut(&mut self) -> &mut [f32; 4] {
cast_mut(self)
}
}
impl From<[f32; 4]> for Vec4 {
#[inline]
fn from([x, y, z, w]: [f32; 4]) -> Self {
cast([x, y, z, w])
}
}
impl From<Vec4> for [f32; 4] {
#[inline]
fn from(v4: Vec4) -> Self {
cast(v4)
}
}
#[cfg(feature = "mint")]
impl From<mint::Vector4<f32>> for Vec4 {
#[inline]
fn from(mint::Vector4 { x, y, z, w }: mint::Vector4<f32>) -> Self {
Self::from([x, y, z, w])
}
}
#[cfg(feature = "mint")]
impl From<Vec4> for mint::Vector4<f32> {
#[inline]
fn from(v: Vec4) -> Self {
let [x, y, z, w]: [f32; 4] = <[f32; 4]>::from(v);
Self { x, y, z, w }
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Vec4 {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
<[f32; 4]>::from(*self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Vec4 {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Self::from(<[f32; 4]>::deserialize(deserializer)?))
}
}
impl Add for Vec4 {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
if_sse! {{
Self { sse: self.sse.add(rhs.sse) }
} else {
Self { arr: [
self.arr[0] + rhs.arr[0],
self.arr[1] + rhs.arr[1],
self.arr[2] + rhs.arr[2],
self.arr[3] + rhs.arr[3],
] }
}}
}
}
impl Add<f32> for Vec4 {
type Output = Self;
#[inline]
fn add(self, rhs: f32) -> Self {
if_sse! {{
Self { sse: self.sse.add(m128::splat(rhs)) }
} else {
Self { arr: [
self.arr[0] + rhs,
self.arr[1] + rhs,
self.arr[2] + rhs,
self.arr[3] + rhs,
] }
}}
}
}
impl Add<Vec4> for f32 {
type Output = Vec4;
#[inline]
fn add(self, rhs: Vec4) -> Vec4 {
Vec4::splat(self) + rhs
}
}
impl AddAssign for Vec4 {
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs
}
}
impl AddAssign<f32> for Vec4 {
#[inline]
fn add_assign(&mut self, rhs: f32) {
*self = *self + rhs
}
}
impl Sub for Vec4 {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
if_sse! {{
Self { sse: self.sse.sub(rhs.sse) }
} else {
Self { arr: [
self.arr[0] - rhs.arr[0],
self.arr[1] - rhs.arr[1],
self.arr[2] - rhs.arr[2],
self.arr[3] - rhs.arr[3],
] }
}}
}
}
impl Sub<f32> for Vec4 {
type Output = Self;
#[inline]
fn sub(self, rhs: f32) -> Self {
if_sse! {{
Self { sse: self.sse.sub(m128::splat(rhs)) }
} else {
Self { arr: [
self.arr[0] - rhs,
self.arr[1] - rhs,
self.arr[2] - rhs,
self.arr[3] - rhs,
] }
}}
}
}
impl Sub<Vec4> for f32 {
type Output = Vec4;
#[inline]
fn sub(self, rhs: Vec4) -> Vec4 {
Vec4::splat(self) - rhs
}
}
impl SubAssign for Vec4 {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs
}
}
impl SubAssign<f32> for Vec4 {
#[inline]
fn sub_assign(&mut self, rhs: f32) {
*self = *self - rhs
}
}
impl Neg for Vec4 {
type Output = Self;
#[inline]
fn neg(self) -> Self {
if_sse! {{
Self { sse: -self.sse }
} else {
Self { arr: [
-self.arr[0],
-self.arr[1],
-self.arr[2],
-self.arr[3],
] }
}}
}
}
impl Mul<f32> for Vec4 {
type Output = Self;
#[inline]
fn mul(self, rhs: f32) -> Self {
if_sse! {{
Self { sse: self.sse.mul(m128::splat(rhs)) }
} else {
Self { arr: [
self.arr[0] * rhs,
self.arr[1] * rhs,
self.arr[2] * rhs,
self.arr[3] * rhs,
] }
}}
}
}
impl Mul<Vec4> for f32 {
type Output = Vec4;
#[inline]
fn mul(self, rhs: Vec4) -> Vec4 {
rhs * self
}
}
impl MulAssign<f32> for Vec4 {
#[inline]
fn mul_assign(&mut self, rhs: f32) {
*self = *self * rhs;
}
}
impl Mul for Vec4 {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
if_sse! {{
Self { sse: self.sse.mul(rhs.sse) }
} else {
Self { arr: [
self.arr[0] * rhs.arr[0],
self.arr[1] * rhs.arr[1],
self.arr[2] * rhs.arr[2],
self.arr[3] * rhs.arr[3],
] }
}}
}
}
impl MulAssign for Vec4 {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl Vec4 {
#[inline(always)]
pub fn x(self) -> f32 {
let [x, _, _, _] = <[f32; 4]>::from(self);
x
}
#[inline(always)]
pub fn y(self) -> f32 {
let [_, y, _, _] = <[f32; 4]>::from(self);
y
}
#[inline(always)]
pub fn z(self) -> f32 {
let [_, _, z, _] = <[f32; 4]>::from(self);
z
}
#[inline(always)]
pub fn w(self) -> f32 {
let [_, _, _, w] = <[f32; 4]>::from(self);
w
}
#[inline(always)]
pub fn x_mut(&mut self) -> &mut f32 {
let arr_mut: &mut [f32; 4] = cast_mut(self);
&mut arr_mut[0]
}
#[inline(always)]
pub fn y_mut(&mut self) -> &mut f32 {
let arr_mut: &mut [f32; 4] = cast_mut(self);
&mut arr_mut[1]
}
#[inline(always)]
pub fn z_mut(&mut self) -> &mut f32 {
let arr_mut: &mut [f32; 4] = cast_mut(self);
&mut arr_mut[2]
}
#[inline(always)]
pub fn w_mut(&mut self) -> &mut f32 {
let arr_mut: &mut [f32; 4] = cast_mut(self);
&mut arr_mut[3]
}
}
impl Vec4 {
#[inline(always)]
pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
Self::from([x, y, z, w])
}
#[inline]
pub fn splat(v: f32) -> Self {
if_sse! {{
Self { sse: m128::splat(v) }
} else {
Self { arr: [v, v, v, v] }
}}
}
#[inline]
pub fn to_vec3(self) -> Vec3 {
Vec3 { v4: self }
}
}
impl Vec4 {
#[inline]
pub fn dot(self, rhs: Self) -> f32 {
if_sse! {{
let square = self * rhs;
let z_w_ = square.zwxx();
let xz_yw_ = square + z_w_;
let yw_ = xz_yw_.yxxx();
let xzyw_ = xz_yw_ + yw_;
xzyw_.sse.extract0_f32()
} else {
let t = self * rhs;
t.x() + t.y() + t.z() + t.w()
}}
}
#[inline]
pub fn length(self) -> f32 {
lokacore::sqrt_f32(self.length2())
}
#[inline]
pub fn length2(self) -> f32 {
let sq = self * self;
sq.x() + sq.y() + sq.z() + sq.w()
}
#[inline]
pub fn normalize(self) -> Self {
let len = self.length();
Self::new(
self.x() / len,
self.y() / len,
self.z() / len,
self.w() / len,
)
}
}