use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; pub use fallback::Float4; mod fallback { use std::ops::{Add, Div, Mul, Neg, Sub}; #[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone)] #[repr(C, align(16))] pub struct Float4 { n: [f32; 4], } impl Float4 { /// Create a new `Float4` with the given components. #[inline(always)] pub fn new(a: f32, b: f32, c: f32, d: f32) -> Self { Self { n: [a, b, c, d] } } /// Create a new `Float4` with all elements set to `n`. #[inline(always)] pub fn splat(n: f32) -> Self { Self { n: [n, n, n, n] } } /// Component-wise fused multiply-add. /// /// `(self * a) + b` with only one rounding error. #[inline(always)] pub fn mul_add(self, a: Self, b: Self) -> Self { Self { n: [ self.n[0].mul_add(a.n[0], b.n[0]), self.n[1].mul_add(a.n[1], b.n[1]), self.n[2].mul_add(a.n[2], b.n[2]), self.n[3].mul_add(a.n[3], b.n[3]), ], } } /// Vertical minimum. #[inline(always)] pub fn min(self, a: Self) -> Self { Self { n: [ self.n[0].min(a.n[0]), self.n[1].min(a.n[1]), self.n[2].min(a.n[2]), self.n[3].min(a.n[3]), ], } } /// Vertical maximum. #[inline(always)] pub fn max(self, a: Self) -> Self { Self { n: [ self.n[0].max(a.n[0]), self.n[1].max(a.n[1]), self.n[2].max(a.n[2]), self.n[3].max(a.n[3]), ], } } // /// Horizontal minimum. // #[inline(always)] // pub fn hmin(self) -> f32 { // let a = self.n[0].min(self.n[1]); // let b = self.n[2].min(self.n[3]); // a.min(b) // } // /// Horizontal maximum. // #[inline(always)] // pub fn hmax(self) -> f32 { // let a = self.n[0].max(self.n[1]); // let b = self.n[2].max(self.n[3]); // a.max(b) // } //----------------------------------------------------- // For matrix stuff. #[inline(always)] pub fn transpose_3x3(m: [Self; 3]) -> [Self; 3] { [ // The fourth component in each row below is arbitrary, // but in this case chosen so that it matches the // behavior of the SSE version of transpose_3x3. Self::new(m[0].a(), m[1].a(), m[2].a(), m[2].d()), Self::new(m[0].b(), m[1].b(), m[2].b(), m[2].d()), Self::new(m[0].c(), m[1].c(), m[2].c(), m[2].d()), ] } #[inline] pub fn invert_3x3(_m: [Self; 3]) -> [Self; 3] { todo!() } #[inline] pub fn invert_3x3_precise(_m: [Self; 3]) -> [Self; 3] { todo!() } //----------------------------------------------------- // Individual components. #[inline(always)] pub fn a(self) -> f32 { self.n[0] } #[inline(always)] pub fn b(self) -> f32 { self.n[1] } #[inline(always)] pub fn c(self) -> f32 { self.n[2] } #[inline(always)] pub fn d(self) -> f32 { self.n[3] } #[inline(always)] #[must_use] pub fn set_a(self, n: f32) -> Self { Self { n: [n, self.n[1], self.n[2], self.n[3]], } } #[inline(always)] #[must_use] pub fn set_b(self, n: f32) -> Self { Self { n: [self.n[0], n, self.n[2], self.n[3]], } } #[inline(always)] #[must_use] pub fn set_c(self, n: f32) -> Self { Self { n: [self.n[0], self.n[1], n, self.n[3]], } } #[inline(always)] #[must_use] pub fn set_d(self, n: f32) -> Self { Self { n: [self.n[0], self.n[1], self.n[2], n], } } //----------------------------------------------------- // Shuffles. #[inline(always)] pub fn aaaa(self) -> Self { let a = self.n[0]; Self { n: [a, a, a, a] } } #[inline(always)] pub fn bbbb(self) -> Self { let b = self.n[1]; Self { n: [b, b, b, b] } } #[inline(always)] pub fn cccc(self) -> Self { let c = self.n[2]; Self { n: [c, c, c, c] } } #[inline(always)] pub fn dddd(self) -> Self { let d = self.n[3]; Self { n: [d, d, d, d] } } } impl Add for Float4 { type Output = Self; #[inline(always)] fn add(self, rhs: Self) -> Self { Self { n: [ self.n[0] + rhs.n[0], self.n[1] + rhs.n[1], self.n[2] + rhs.n[2], self.n[3] + rhs.n[3], ], } } } impl Sub for Float4 { type Output = Self; #[inline(always)] fn sub(self, rhs: Self) -> Self { Self { n: [ self.n[0] - rhs.n[0], self.n[1] - rhs.n[1], self.n[2] - rhs.n[2], self.n[3] - rhs.n[3], ], } } } impl Mul for Float4 { type Output = Self; #[inline(always)] fn mul(self, rhs: Self) -> Self { Self { n: [ self.n[0] * rhs.n[0], self.n[1] * rhs.n[1], self.n[2] * rhs.n[2], self.n[3] * rhs.n[3], ], } } } impl Mul for Float4 { type Output = Self; #[inline(always)] fn mul(self, rhs: f32) -> Self { Self { n: [ self.n[0] * rhs, self.n[1] * rhs, self.n[2] * rhs, self.n[3] * rhs, ], } } } impl Div for Float4 { type Output = Self; #[inline(always)] fn div(self, rhs: Self) -> Self { Self { n: [ self.n[0] / rhs.n[0], self.n[1] / rhs.n[1], self.n[2] / rhs.n[2], self.n[3] / rhs.n[3], ], } } } impl Div for Float4 { type Output = Self; #[inline(always)] fn div(self, rhs: f32) -> Self { Self { n: [ self.n[0] / rhs, self.n[1] / rhs, self.n[2] / rhs, self.n[3] / rhs, ], } } } impl Neg for Float4 { type Output = Self; #[inline(always)] fn neg(self) -> Self { Self { n: [-self.n[0], -self.n[1], -self.n[2], -self.n[3]], } } } } //------------------------------------------------------------- impl AddAssign for Float4 { #[inline(always)] fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; } } impl SubAssign for Float4 { #[inline(always)] fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; } } impl MulAssign for Float4 { #[inline(always)] fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; } } impl MulAssign for Float4 { #[inline(always)] fn mul_assign(&mut self, rhs: f32) { *self = *self * rhs; } } impl DivAssign for Float4 { #[inline(always)] fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } } impl DivAssign for Float4 { #[inline(always)] fn div_assign(&mut self, rhs: f32) { *self = *self / rhs; } }