#![allow(dead_code)]
#[cfg(feature = "rand")]
use rand::{
distributions::{Distribution, Standard},
Rng,
};
use crate::{f32::Vec3, Align16};
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
use std::{cmp::Ordering, f32, fmt, mem::MaybeUninit, ops::*};
pub(crate) const X_AXIS: Align16<(f32, f32, f32, f32)> = Align16((1.0, 0.0, 0.0, 0.0));
pub(crate) const Y_AXIS: Align16<(f32, f32, f32, f32)> = Align16((0.0, 1.0, 0.0, 0.0));
pub(crate) const Z_AXIS: Align16<(f32, f32, f32, f32)> = Align16((0.0, 0.0, 1.0, 0.0));
pub(crate) const W_AXIS: Align16<(f32, f32, f32, f32)> = Align16((0.0, 0.0, 0.0, 1.0));
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct Vec4(pub(crate) __m128);
impl Vec4 {
#[inline]
pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
unsafe { Self(_mm_set_ps(w, z, y, x)) }
}
#[inline]
pub fn zero() -> Self {
unsafe { Self(_mm_set1_ps(0.0)) }
}
#[inline]
pub fn one() -> Self {
unsafe { Self(_mm_set1_ps(1.0)) }
}
#[inline]
pub fn unit_x() -> Self {
unsafe {
Self(_mm_load_ps(
&X_AXIS as *const Align16<(f32, f32, f32, f32)> as *const f32,
))
}
}
#[inline]
pub fn unit_y() -> Self {
unsafe {
Self(_mm_load_ps(
&Y_AXIS as *const Align16<(f32, f32, f32, f32)> as *const f32,
))
}
}
#[inline]
pub fn unit_z() -> Self {
unsafe {
Self(_mm_load_ps(
&Z_AXIS as *const Align16<(f32, f32, f32, f32)> as *const f32,
))
}
}
#[inline]
pub fn unit_w() -> Self {
unsafe {
Self(_mm_load_ps(
&W_AXIS as *const Align16<(f32, f32, f32, f32)> as *const f32,
))
}
}
#[inline]
pub fn splat(v: f32) -> Self {
unsafe { Self(_mm_set_ps1(v)) }
}
#[inline]
pub fn truncate(self) -> Vec3 {
self.0.into()
}
#[inline]
pub fn x(self) -> f32 {
unsafe { _mm_cvtss_f32(self.0) }
}
#[inline]
pub fn y(self) -> f32 {
unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) }
}
#[inline]
pub fn z(self) -> f32 {
unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) }
}
#[inline]
pub fn w(self) -> f32 {
unsafe { _mm_cvtss_f32(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_11)) }
}
#[inline]
pub fn set_x(&mut self, x: f32) {
unsafe {
self.0 = _mm_move_ss(self.0, _mm_set_ss(x));
}
}
#[inline]
pub fn set_y(&mut self, y: f32) {
unsafe {
let mut t = _mm_move_ss(self.0, _mm_set_ss(y));
t = _mm_shuffle_ps(t, t, 0b11_10_00_00);
self.0 = _mm_move_ss(t, self.0);
}
}
#[inline]
pub fn set_z(&mut self, z: f32) {
unsafe {
let mut t = _mm_move_ss(self.0, _mm_set_ss(z));
t = _mm_shuffle_ps(t, t, 0b11_00_01_00);
self.0 = _mm_move_ss(t, self.0);
}
}
#[inline]
pub fn set_w(&mut self, w: f32) {
unsafe {
let mut t = _mm_move_ss(self.0, _mm_set_ss(w));
t = _mm_shuffle_ps(t, t, 0b00_10_01_00);
self.0 = _mm_move_ss(t, self.0);
}
}
#[inline]
pub(crate) fn dup_x(self) -> Self {
unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b00_00_00_00)) }
}
#[inline]
pub(crate) fn dup_y(self) -> Self {
unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b01_01_01_01)) }
}
#[inline]
pub(crate) fn dup_z(self) -> Self {
unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b10_10_10_10)) }
}
#[inline]
pub(crate) fn dup_w(self) -> Self {
unsafe { Self(_mm_shuffle_ps(self.0, self.0, 0b11_11_11_11)) }
}
#[inline]
unsafe fn dot_as_m128(self, other: Self) -> __m128 {
let x2_y2_z2_w2 = _mm_mul_ps(self.0, other.0);
let z2_w2_0_0 = _mm_shuffle_ps(x2_y2_z2_w2, x2_y2_z2_w2, 0b00_00_11_10);
let x2z2_y2w2_0_0 = _mm_add_ps(x2_y2_z2_w2, z2_w2_0_0);
let y2w2_0_0_0 = _mm_shuffle_ps(x2z2_y2w2_0_0, x2z2_y2w2_0_0, 0b00_00_00_01);
_mm_add_ps(x2z2_y2w2_0_0, y2w2_0_0_0)
}
#[inline]
fn dot_as_vec4(self, other: Self) -> Self {
unsafe {
let dot_in_x = self.dot_as_m128(other);
Self(_mm_shuffle_ps(dot_in_x, dot_in_x, 0b00_00_00_00))
}
}
#[inline]
pub fn dot(self, other: Self) -> f32 {
unsafe { _mm_cvtss_f32(self.dot_as_m128(other)) }
}
#[inline]
pub fn length(self) -> f32 {
let dot = self.dot_as_vec4(self);
unsafe { _mm_cvtss_f32(_mm_sqrt_ps(dot.0)) }
}
#[inline]
pub fn length_squared(self) -> f32 {
self.dot(self)
}
#[inline]
pub fn length_reciprocal(self) -> f32 {
let dot = self.dot_as_vec4(self);
unsafe {
_mm_cvtss_f32(_mm_div_ps(_mm_set_ps1(1.0), _mm_sqrt_ps(dot.0)))
}
}
#[inline]
pub fn normalize(self) -> Self {
let dot = self.dot_as_vec4(self);
unsafe { Self(_mm_div_ps(self.0, _mm_sqrt_ps(dot.0))) }
}
#[inline]
pub fn min(self, other: Self) -> Self {
unsafe { Self(_mm_min_ps(self.0, other.0)) }
}
#[inline]
pub fn max(self, other: Self) -> Self {
unsafe { Self(_mm_max_ps(self.0, other.0)) }
}
#[inline]
pub fn min_element(self) -> f32 {
unsafe {
let v = self.0;
let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10));
let v = _mm_min_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01));
_mm_cvtss_f32(v)
}
}
#[inline]
pub fn max_element(self) -> f32 {
unsafe {
let v = self.0;
let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_11_10));
let v = _mm_max_ps(v, _mm_shuffle_ps(v, v, 0b00_00_00_01));
_mm_cvtss_f32(v)
}
}
#[inline]
pub fn cmpeq(self, other: Self) -> Vec4Mask {
unsafe { Vec4Mask(_mm_cmpeq_ps(self.0, other.0)) }
}
#[inline]
pub fn cmpne(self, other: Self) -> Vec4Mask {
unsafe { Vec4Mask(_mm_cmpneq_ps(self.0, other.0)) }
}
#[inline]
pub fn cmpge(self, other: Self) -> Vec4Mask {
unsafe { Vec4Mask(_mm_cmpge_ps(self.0, other.0)) }
}
#[inline]
pub fn cmpgt(self, other: Self) -> Vec4Mask {
unsafe { Vec4Mask(_mm_cmpgt_ps(self.0, other.0)) }
}
#[inline]
pub fn cmple(self, other: Self) -> Vec4Mask {
unsafe { Vec4Mask(_mm_cmple_ps(self.0, other.0)) }
}
#[inline]
pub fn cmplt(self, other: Self) -> Vec4Mask {
unsafe { Vec4Mask(_mm_cmplt_ps(self.0, other.0)) }
}
#[inline]
pub fn from_slice_unaligned(slice: &[f32]) -> Self {
assert!(slice.len() >= 4);
unsafe { Self(_mm_loadu_ps(slice.as_ptr())) }
}
#[inline]
pub fn write_to_slice_unaligned(self, slice: &mut [f32]) {
unsafe {
assert!(slice.len() >= 4);
_mm_storeu_ps(slice.as_mut_ptr(), self.0);
}
}
#[inline]
pub(crate) fn mul_add(self, a: Self, b: Self) -> Self {
unsafe { Self(_mm_add_ps(_mm_mul_ps(self.0, a.0), b.0)) }
}
#[inline]
pub(crate) fn neg_mul_sub(self, a: Self, b: Self) -> Self {
unsafe { Self(_mm_sub_ps(b.0, _mm_mul_ps(self.0, a.0))) }
}
#[inline]
pub fn abs(self) -> Self {
unsafe {
Self(_mm_and_ps(
self.0,
_mm_castsi128_ps(_mm_set1_epi32(0x7f_ff_ff_ff)),
))
}
}
}
impl fmt::Display for Vec4 {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let (x, y, z, w) = (*self).into();
write!(fmt, "[{}, {}, {}, {}]", x, y, z, w)
}
}
impl Div<Vec4> for Vec4 {
type Output = Self;
#[inline]
fn div(self, other: Self) -> Self {
unsafe { Self(_mm_div_ps(self.0, other.0)) }
}
}
impl DivAssign<Vec4> for Vec4 {
#[inline]
fn div_assign(&mut self, other: Self) {
unsafe {
self.0 = _mm_div_ps(self.0, other.0);
}
}
}
impl Div<f32> for Vec4 {
type Output = Self;
#[inline]
fn div(self, other: f32) -> Self {
unsafe { Self(_mm_div_ps(self.0, _mm_set1_ps(other))) }
}
}
impl DivAssign<f32> for Vec4 {
#[inline]
fn div_assign(&mut self, other: f32) {
unsafe { self.0 = _mm_div_ps(self.0, _mm_set1_ps(other)) }
}
}
impl Mul<Vec4> for Vec4 {
type Output = Self;
#[inline]
fn mul(self, other: Self) -> Self {
unsafe { Self(_mm_mul_ps(self.0, other.0)) }
}
}
impl MulAssign<Vec4> for Vec4 {
#[inline]
fn mul_assign(&mut self, other: Self) {
unsafe {
self.0 = _mm_mul_ps(self.0, other.0);
}
}
}
impl Mul<f32> for Vec4 {
type Output = Self;
#[inline]
fn mul(self, other: f32) -> Self {
unsafe { Self(_mm_mul_ps(self.0, _mm_set1_ps(other))) }
}
}
impl MulAssign<f32> for Vec4 {
#[inline]
fn mul_assign(&mut self, other: f32) {
unsafe { self.0 = _mm_mul_ps(self.0, _mm_set1_ps(other)) }
}
}
impl Mul<Vec4> for f32 {
type Output = Vec4;
#[inline]
fn mul(self, other: Vec4) -> Vec4 {
unsafe { Vec4(_mm_mul_ps(_mm_set1_ps(self), other.0)) }
}
}
impl Add for Vec4 {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
unsafe { Self(_mm_add_ps(self.0, other.0)) }
}
}
impl AddAssign for Vec4 {
#[inline]
fn add_assign(&mut self, other: Self) {
unsafe { self.0 = _mm_add_ps(self.0, other.0) }
}
}
impl Sub for Vec4 {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
unsafe { Self(_mm_sub_ps(self.0, other.0)) }
}
}
impl SubAssign for Vec4 {
#[inline]
fn sub_assign(&mut self, other: Self) {
unsafe { self.0 = _mm_sub_ps(self.0, other.0) }
}
}
impl Neg for Vec4 {
type Output = Self;
#[inline]
fn neg(self) -> Self {
unsafe { Self(_mm_sub_ps(_mm_set1_ps(0.0), self.0)) }
}
}
impl Default for Vec4 {
#[inline]
fn default() -> Self {
Self::zero()
}
}
impl PartialEq for Vec4 {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.cmpeq(*other).all()
}
}
impl PartialOrd for Vec4 {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_ref().partial_cmp(other.as_ref())
}
}
impl From<Vec4> for __m128 {
#[cfg_attr(tarpaulin, skip)]
#[inline]
fn from(t: Vec4) -> Self {
t.0
}
}
impl From<__m128> for Vec4 {
#[inline]
fn from(t: __m128) -> Self {
Self(t)
}
}
impl From<(f32, f32, f32, f32)> for Vec4 {
#[inline]
fn from(t: (f32, f32, f32, f32)) -> Self {
Self::new(t.0, t.1, t.2, t.3)
}
}
impl From<Vec4> for (f32, f32, f32, f32) {
#[inline]
fn from(v: Vec4) -> Self {
let mut out: MaybeUninit<Align16<(f32, f32, f32, f32)>> = MaybeUninit::uninit();
unsafe {
_mm_store_ps(out.as_mut_ptr() as *mut f32, v.0);
out.assume_init().0
}
}
}
impl From<[f32; 4]> for Vec4 {
#[inline]
fn from(a: [f32; 4]) -> Self {
unsafe { Self(_mm_loadu_ps(a.as_ptr())) }
}
}
impl From<Vec4> for [f32; 4] {
#[inline]
fn from(v: Vec4) -> Self {
let mut out: MaybeUninit<Align16<[f32; 4]>> = MaybeUninit::uninit();
unsafe {
_mm_store_ps(out.as_mut_ptr() as *mut f32, v.0);
out.assume_init().0
}
}
}
#[cfg(feature = "rand")]
impl Distribution<Vec4> for Standard {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec4 {
rng.gen::<[f32; 4]>().into()
}
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct Vec4Mask(__m128);
impl Vec4Mask {
#[inline]
pub fn new(x: bool, y: bool, z: bool, w: bool) -> Self {
const MASK: [u32; 2] = [0, 0xff_ff_ff_ff];
unsafe {
Self(_mm_set_ps(
f32::from_bits(MASK[w as usize]),
f32::from_bits(MASK[z as usize]),
f32::from_bits(MASK[y as usize]),
f32::from_bits(MASK[x as usize]),
))
}
}
#[inline]
pub fn bitmask(self) -> u32 {
unsafe { (_mm_movemask_ps(self.0) as u32) }
}
#[inline]
pub fn any(self) -> bool {
unsafe { _mm_movemask_ps(self.0) != 0 }
}
#[inline]
pub fn all(self) -> bool {
unsafe { _mm_movemask_ps(self.0) == 0xf }
}
#[inline]
pub fn select(self, if_true: Vec4, if_false: Vec4) -> Vec4 {
unsafe {
Vec4(_mm_or_ps(
_mm_andnot_ps(self.0, if_false.0),
_mm_and_ps(if_true.0, self.0),
))
}
}
}
impl Default for Vec4Mask {
#[inline]
fn default() -> Self {
unsafe { Self(_mm_setzero_ps()) }
}
}
impl BitAnd for Vec4Mask {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self {
unsafe { Self(_mm_and_ps(self.0, other.0)) }
}
}
impl BitAndAssign for Vec4Mask {
fn bitand_assign(&mut self, other: Self) {
*self = *self & other
}
}
impl BitOr for Vec4Mask {
type Output = Self;
#[inline]
fn bitor(self, other: Self) -> Self {
unsafe { Self(_mm_or_ps(self.0, other.0)) }
}
}
impl BitOrAssign for Vec4Mask {
fn bitor_assign(&mut self, other: Self) {
*self = *self | other
}
}
impl Not for Vec4Mask {
type Output = Self;
#[inline]
fn not(self) -> Self {
unsafe {
Self(_mm_andnot_ps(
self.0,
_mm_set_ps1(f32::from_bits(0xff_ff_ff_ff)),
))
}
}
}