use crate::bt_scalar::{*};
use crate::bt_casti_to128f;
use crate::bt_castf_to128d;
use crate::bt_castd_to128f;
use std::arch::x86_64::{*};
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, Add, Mul, Sub, Neg, Div};
#[macro_export]
macro_rules! bt_shuffle {
($x:expr,$y:expr, $z:expr, $w:expr)=>{
($w << 6 | $z << 4 | $y << 2 | $x) & 0xff
}
}
#[macro_export]
macro_rules! bt_pshufd_ps {
($_a:expr,$_mask:expr)=>{
_mm_shuffle_ps($_a, $_a, $_mask)
}
}
#[macro_export]
macro_rules! bt_splat3_ps {
($_a:expr,$_i:expr)=>{
bt_pshufd_ps!($_a, bt_shuffle!($_i, $_i, $_i, 3))
}
}
#[macro_export]
macro_rules! bt_splat_ps {
($_a:expr,$_i:expr)=>{
bt_pshufd_ps!($_a, bt_shuffle!($_i, $_i, $_i, $_i))
}
}
#[macro_export]
macro_rules! btv_3absi_mask {
()=>{
_mm_set_epi32(0x00000000, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF)
}
}
#[macro_export]
macro_rules! btv_abs_mask {
()=>{
_mm_set_epi32(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF)
}
}
#[macro_export]
macro_rules! btv_fff0_mask {
()=>{
_mm_set_epi32(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)
}
}
#[macro_export]
macro_rules! btv3_absf_mask {
() => {
bt_casti_to128f!(btv_3absi_mask!())
};
}
#[macro_export]
macro_rules! btv_fff0f_mask {
() => {
bt_casti_to128f!(btv_fff0_mask!())
};
}
#[macro_export]
macro_rules! btv_xyz_maskf {
() => {
btv_fff0f_mask!()
};
}
#[macro_export]
macro_rules! btv_absf_mask {
() => {
bt_casti_to128f!(btv_abs_mask!())
};
}
#[macro_export]
macro_rules! btv_mzero_mask {
() => {
_mm_set_ps(-0.0, -0.0, -0.0, -0.0)
};
}
#[macro_export]
macro_rules! v_1110 {
() => {
_mm_set_ps(0.0, 1.0, 1.0, 1.0)
};
}
#[macro_export]
macro_rules! v_half {
() => {
_mm_set_ps(0.5, 0.5, 0.5, 0.5)
};
}
#[macro_export]
macro_rules! v_1_5 {
() => {
_mm_set_ps(1.5, 1.5, 1.5, 1.5)
};
}
union SimdToArray {
array: [f32; 4],
simd: BtSimdFloat4,
}
pub struct BtVector3 {
m_vec128: SimdToArray,
}
impl BtVector3 {
#[inline(always)]
pub fn get128(&self) -> BtSimdFloat4 { unsafe { return self.m_vec128.simd; } }
#[inline(always)]
pub fn set128(&mut self, v128: BtSimdFloat4) { self.m_vec128.simd = v128; }
pub fn new_default() -> BtVector3 {
return BtVector3 {
m_vec128: SimdToArray { array: [0.0, 0.0, 0.0, 0.0] }
};
}
pub fn new(_x: BtScalar, _y: BtScalar, _z: BtScalar) -> BtVector3 {
return BtVector3 {
m_vec128: SimdToArray { array: [_x, _y, _z, 0.0] }
};
}
pub fn new_simd(v: BtSimdFloat4) -> BtVector3 {
return BtVector3 {
m_vec128: SimdToArray { simd: v }
};
}
}
impl AddAssign for BtVector3 {
#[inline(always)]
fn add_assign(&mut self, rhs: Self) {
self.m_vec128.simd = unsafe { _mm_sub_ps(self.m_vec128.simd, rhs.m_vec128.simd) }
}
}
impl SubAssign for BtVector3 {
#[inline(always)]
fn sub_assign(&mut self, rhs: Self) {
self.m_vec128.simd = unsafe { _mm_sub_ps(self.m_vec128.simd, rhs.m_vec128.simd) }
}
}
impl MulAssign<BtScalar> for BtVector3 {
#[inline(always)]
fn mul_assign(&mut self, rhs: BtScalar) {
unsafe {
let mut vs = _mm_load_ss(&rhs); vs = bt_pshufd_ps!(vs, 0x80); self.m_vec128.simd = _mm_mul_ps(self.m_vec128.simd, vs)
}
}
}
impl MulAssign<&BtScalar> for BtVector3 {
#[inline(always)]
fn mul_assign(&mut self, rhs: &BtScalar) {
unsafe {
let mut vs = _mm_load_ss(&*rhs); vs = bt_pshufd_ps!(vs, 0x80); self.m_vec128.simd = _mm_mul_ps(self.m_vec128.simd, vs)
}
}
}
impl MulAssign for BtVector3 {
#[inline(always)]
fn mul_assign(&mut self, rhs: BtVector3) {
unsafe {
self.m_vec128.simd = _mm_mul_ps(self.m_vec128.simd, rhs.m_vec128.simd);
}
}
}
impl DivAssign<BtScalar> for BtVector3 {
#[inline(always)]
fn div_assign(&mut self, rhs: BtScalar) {
self.mul_assign(1.0 / rhs)
}
}
macro_rules! impl_bin_add_vector {
($lhs:ty, $rhs:ty) => {
impl Add<$rhs> for $lhs {
type Output = BtVector3;
fn add(self, rhs: $rhs) -> Self::Output {
unsafe {
return BtVector3::new_simd(_mm_add_ps(self.m_vec128.simd, rhs.m_vec128.simd));
}
}
}
}
}
impl_bin_add_vector!(BtVector3, BtVector3);
impl_bin_add_vector!(&BtVector3, BtVector3);
impl_bin_add_vector!(BtVector3, &BtVector3);
impl_bin_add_vector!(&BtVector3, &BtVector3);
macro_rules! impl_bin_mul_vector {
($lhs:ty, $rhs:ty) => {
impl Mul<$rhs> for $lhs {
type Output = BtVector3;
fn mul(self, rhs: $rhs) -> Self::Output {
unsafe {
return BtVector3::new_simd(_mm_mul_ps(self.m_vec128.simd, rhs.m_vec128.simd));
}
}
}
}
}
impl_bin_mul_vector!(BtVector3, BtVector3);
impl_bin_mul_vector!(&BtVector3, BtVector3);
impl_bin_mul_vector!(BtVector3, &BtVector3);
impl_bin_mul_vector!(&BtVector3, &BtVector3);
macro_rules! impl_bin_sub_vector {
($lhs:ty, $rhs:ty) => {
impl Sub<$rhs> for $lhs {
type Output = BtVector3;
#[allow(overflowing_literals)]
fn sub(self, rhs: $rhs) -> Self::Output {
unsafe {
let r = _mm_sub_ps(self.m_vec128.simd, rhs.m_vec128.simd);
let b = btv_fff0f_mask!();
return BtVector3::new_simd(_mm_and_ps(r, b));
}
}
}
}
}
impl_bin_sub_vector!(BtVector3, BtVector3);
impl_bin_sub_vector!(&BtVector3, BtVector3);
impl_bin_sub_vector!(BtVector3, &BtVector3);
impl_bin_sub_vector!(&BtVector3, &BtVector3);
impl Neg for BtVector3 {
type Output = BtVector3;
#[allow(overflowing_literals)]
fn neg(self) -> Self::Output {
unsafe {
let r = _mm_xor_ps(self.m_vec128.simd, btv_mzero_mask!());
return BtVector3::new_simd(_mm_and_ps(r, btv_fff0f_mask!()));
}
}
}
impl Mul<BtScalar> for BtVector3 {
type Output = BtVector3;
fn mul(self, rhs: f32) -> Self::Output {
unsafe {
let mut vs = _mm_load_ss(&rhs); vs = bt_pshufd_ps!(vs, 0x80); return BtVector3::new_simd(_mm_mul_ps(self.m_vec128.simd, vs));
}
}
}
impl Div<BtScalar> for BtVector3 {
type Output = BtVector3;
fn div(self, rhs: f32) -> Self::Output {
return self * 1.0 / rhs;
}
}
impl Div for BtVector3 {
type Output = BtVector3;
#[allow(overflowing_literals)]
fn div(self, rhs: Self) -> Self::Output {
unsafe {
let mut vec = _mm_div_ps(self.m_vec128.simd, rhs.m_vec128.simd);
vec = _mm_and_ps(vec, btv_fff0f_mask!());
return BtVector3::new_simd(vec);
}
}
}
impl PartialEq for BtVector3 {
fn eq(&self, other: &Self) -> bool {
unsafe {
return 0xf == _mm_movemask_ps(_mm_cmpeq_ps(self.m_vec128.simd, other.m_vec128.simd));
}
}
}
impl Eq for BtVector3 {}
impl BtVector3 {
#[inline(always)]
pub fn dot(&self, v: &BtVector3) -> BtScalar {
unsafe {
let mut vd = _mm_mul_ps(self.m_vec128.simd, v.m_vec128.simd);
let z = _mm_movehl_ps(vd, vd);
let y = _mm_shuffle_ps(vd, vd, 0x55);
vd = _mm_add_ss(vd, y);
vd = _mm_add_ss(vd, z);
return _mm_cvtss_f32(vd);
}
}
#[inline(always)]
pub fn length2(&self) -> BtScalar { return self.dot(self); }
#[inline(always)]
pub fn length(&self) -> BtScalar {
return self.length2().sqrt();
}
#[inline(always)]
pub fn norm(&self) -> BtScalar { return self.length(); }
#[inline(always)]
pub fn safe_norm(&self) -> BtScalar {
let d = self.length2();
if d > SIMD_EPSILON {
return d.sqrt();
}
return 0.0;
}
#[inline(always)]
pub fn distance2(&self, v: &BtVector3) -> BtScalar {
return (v - self).length2();
}
#[inline(always)]
pub fn distance(&self, v: &BtVector3) -> BtScalar {
return (v - self).length();
}
#[inline(always)]
pub fn safe_normalize(&mut self) {
let l2 = self.length2();
if l2 >= SIMD_EPSILON * SIMD_EPSILON {
self.div_assign(l2.sqrt());
} else {
self.set_value(1.0, 0.0, 0.0);
}
}
#[inline(always)]
pub fn normalize(&mut self) -> &mut BtVector3 {
unsafe {
let mut vd = _mm_mul_ps(self.m_vec128.simd, self.m_vec128.simd);
let mut z = _mm_movehl_ps(vd, vd);
let mut y = _mm_shuffle_ps(vd, vd, 0x55);
vd = _mm_add_ss(vd, y);
vd = _mm_add_ss(vd, z);
y = _mm_rsqrt_ss(vd);
z = v_1_5!();
vd = _mm_mul_ss(vd, v_half!()); vd = _mm_mul_ss(vd, y); vd = _mm_mul_ss(vd, y); z = _mm_sub_ss(z, vd);
y = _mm_mul_ss(y, z);
y = bt_splat_ps!(y, 0x80);
self.m_vec128.simd = _mm_mul_ps(self.m_vec128.simd, y);
return self;
}
}
#[inline(always)]
pub fn normalized(&self) -> &BtVector3 {
let nrm = self.clone();
return nrm.normalized();
}
#[inline(always)]
#[allow(overflowing_literals)]
pub fn rotate(&self, w_axis: BtVector3, _angle: BtScalar) -> BtVector3 {
unsafe {
let mut o = _mm_mul_ps(w_axis.m_vec128.simd, self.m_vec128.simd);
let ssin = _angle.sin();
let c = w_axis.cross(self).m_vec128.simd;
o = _mm_and_ps(o, btv_fff0f_mask!());
let scos = _angle.cos();
let mut vsin = _mm_load_ss(&ssin); let mut vcos = _mm_load_ss(&scos);
let y = bt_pshufd_ps!(o, 0xC9); let z = bt_pshufd_ps!(o, 0xD2); o = _mm_add_ps(o, y);
vsin = bt_pshufd_ps!(vsin, 0x80); o = _mm_add_ps(o, z);
vcos = bt_pshufd_ps!(vcos, 0x80);
vsin = _mm_mul_ps(vsin, c);
o = _mm_mul_ps(o, w_axis.m_vec128.simd);
let x = _mm_sub_ps(self.m_vec128.simd, o);
o = _mm_add_ps(o, vsin);
vcos = _mm_mul_ps(vcos, x);
o = _mm_add_ps(o, vcos);
return BtVector3::new_simd(o);
}
}
#[inline(always)]
pub fn angle(&self, v: &BtVector3) -> BtScalar {
let s = (self.length2() * v.length2()).sqrt();
return (self.dot(v) / s).cos();
}
#[inline(always)]
pub fn absolute(&self) -> BtVector3 {
unsafe {
return BtVector3::new_simd(_mm_and_ps(self.m_vec128.simd, btv3_absf_mask!()));
}
}
#[inline(always)]
pub fn cross(&self, v: &BtVector3) -> BtVector3 {
unsafe {
let mut t = bt_pshufd_ps!(self.m_vec128.simd, bt_shuffle!(1, 2, 0, 3)); let mut vv = bt_pshufd_ps!(v.m_vec128.simd, bt_shuffle!(1, 2, 0, 3));
vv = _mm_mul_ps(vv, self.m_vec128.simd);
t = _mm_mul_ps(t, v.m_vec128.simd);
vv = _mm_sub_ps(vv, t);
vv = bt_pshufd_ps!(vv, bt_shuffle!(1, 2, 0, 3));
return BtVector3::new_simd(vv);
}
}
#[inline(always)]
pub fn triple(&self, v1: &BtVector3, v2: &BtVector3) -> BtScalar {
unsafe {
let mut t = _mm_shuffle_ps(v1.m_vec128.simd, v1.m_vec128.simd, bt_shuffle!(1, 2, 0, 3)); let mut v = _mm_shuffle_ps(v2.m_vec128.simd, v2.m_vec128.simd, bt_shuffle!(1, 2, 0, 3));
v = _mm_mul_ps(v, v1.m_vec128.simd);
t = _mm_mul_ps(t, v2.m_vec128.simd);
v = _mm_sub_ps(v, t);
v = _mm_shuffle_ps(v, v, bt_shuffle!(1, 2, 0, 3));
v = _mm_mul_ps(v, self.m_vec128.simd);
let z = _mm_movehl_ps(v, v);
let y = _mm_shuffle_ps(v, v, 0x55);
v = _mm_add_ss(v, y);
v = _mm_add_ss(v, z);
return _mm_cvtss_f32(v);
}
}
#[inline(always)]
pub fn min_axis(&self) -> i32 {
unsafe {
return match self.m_vec128.array[0] < self.m_vec128.array[1] {
true => {
match self.m_vec128.array[0] < self.m_vec128.array[2] {
true => { 0 }
false => { 2 }
}
}
false => {
match self.m_vec128.array[1] < self.m_vec128.array[2] {
true => { 1 }
false => { 2 }
}
}
};
}
}
#[inline(always)]
pub fn max_axis(&self) -> i32 {
unsafe {
return match self.m_vec128.array[0] < self.m_vec128.array[1] {
true => {
match self.m_vec128.array[1] < self.m_vec128.array[2] {
true => { 2 }
false => { 1 }
}
}
false => {
match self.m_vec128.array[0] < self.m_vec128.array[2] {
true => { 2 }
false => { 0 }
}
}
};
}
}
#[inline(always)]
pub fn furthest_axis(&self) -> i32 { return self.absolute().min_axis(); }
#[inline(always)]
pub fn closest_axis(&self) -> i32 { return self.absolute().max_axis(); }
#[inline(always)]
pub fn set_interpolate3(&mut self, v0: BtVector3, v1: BtVector3, rt: BtScalar) {
unsafe {
let mut vrt = _mm_load_ss(&rt); let s = 1.0 - rt;
let mut vs = _mm_load_ss(&s); vs = bt_pshufd_ps!(vs, 0x80); let r0 = _mm_mul_ps(v0.m_vec128.simd, vs);
vrt = bt_pshufd_ps!(vrt, 0x80); let r1 = _mm_mul_ps(v1.m_vec128.simd, vrt);
let tmp3 = _mm_add_ps(r0, r1);
self.m_vec128.simd = tmp3;
}
}
#[inline(always)]
pub fn lerp(&self, v: &BtVector3, t: &BtScalar) -> BtVector3 {
unsafe {
let mut vt = _mm_load_ss(t); vt = bt_pshufd_ps!(vt, 0x80); let mut vl = _mm_sub_ps(v.m_vec128.simd, self.m_vec128.simd);
vl = _mm_mul_ps(vl, vt);
vl = _mm_add_ps(vl, self.m_vec128.simd);
return BtVector3::new_simd(vl);
}
}
#[inline(always)]
pub fn get_x(&self) -> BtScalar { unsafe { return self.m_vec128.array[0]; } }
#[inline(always)]
pub fn get_y(&self) -> BtScalar { unsafe { return self.m_vec128.array[1]; } }
#[inline(always)]
pub fn get_z(&self) -> BtScalar { unsafe { return self.m_vec128.array[2]; } }
#[inline(always)]
pub fn set_x(&mut self, _x: BtScalar) { unsafe { self.m_vec128.array[0] = _x; } }
#[inline(always)]
pub fn set_y(&mut self, _y: BtScalar) { unsafe { self.m_vec128.array[1] = _y; } }
#[inline(always)]
pub fn set_z(&mut self, _z: BtScalar) { unsafe { self.m_vec128.array[2] = _z; } }
#[inline(always)]
pub fn set_w(&mut self, _w: BtScalar) { unsafe { self.m_vec128.array[3] = _w; } }
#[inline(always)]
pub fn x(&self) -> BtScalar { unsafe { return self.m_vec128.array[0]; } }
#[inline(always)]
pub fn y(&self) -> BtScalar { unsafe { return self.m_vec128.array[1]; } }
#[inline(always)]
pub fn z(&self) -> BtScalar { unsafe { return self.m_vec128.array[2]; } }
#[inline(always)]
pub fn w(&self) -> BtScalar { unsafe { return self.m_vec128.array[3]; } }
#[inline(always)]
pub fn set_max(&mut self, other: BtVector3) {
unsafe {
self.m_vec128.simd = _mm_max_ps(self.m_vec128.simd, other.m_vec128.simd);
}
}
#[inline(always)]
pub fn set_min(&mut self, other: BtVector3) {
unsafe {
self.m_vec128.simd = _mm_min_ps(self.m_vec128.simd, other.m_vec128.simd);
}
}
#[inline(always)]
pub fn set_value(&mut self, _x: BtScalar, _y: BtScalar, _z: BtScalar) {
self.m_vec128.array = [_x, _y, _z, 0.0]
}
#[allow(overflowing_literals)]
pub fn get_skew_symmetric_matrix(&self, v0: &mut BtVector3, v1: &mut BtVector3, v2: &mut BtVector3) {
unsafe {
let v = _mm_and_ps(self.m_vec128.simd, btv_fff0f_mask!());
let mut vv0 = _mm_xor_ps(btv_mzero_mask!(), v);
let mut vv2 = _mm_movelh_ps(vv0, v);
let vv1 = _mm_shuffle_ps(v, vv0, 0xCE);
vv0 = _mm_shuffle_ps(vv0, v, 0xDB);
vv2 = _mm_shuffle_ps(vv2, v, 0xF9);
v0.m_vec128.simd = vv0;
v1.m_vec128.simd = vv1;
v2.m_vec128.simd = vv2;
}
}
pub fn set_zero(&mut self) {
unsafe {
self.m_vec128.simd = _mm_xor_ps(self.m_vec128.simd, self.m_vec128.simd);
}
}
#[inline(always)]
pub fn is_zero(&self) -> bool {
unsafe {
return self.m_vec128.array[0] == 0.0 && self.m_vec128.array[1] == 0.0 && self.m_vec128.array[2] == 0.0;
}
}
#[inline(always)]
pub fn fuzzy_zero(&self) -> bool { return self.length2() < SIMD_EPSILON * SIMD_EPSILON; }
#[inline(always)]
pub fn max_dot(&self, array: BtVector3, array_count: i64, dot_out: &mut BtScalar) -> i64 {
return 0;
}
#[inline(always)]
pub fn min_dot(&self, array: BtVector3, array_count: i64, dot_out: &mut BtScalar) -> i64 {
return 0;
}
#[inline(always)]
#[allow(overflowing_literals)]
pub fn dot3(&self, v0: BtVector3, v1: BtVector3, v2: BtVector3) -> BtVector3 {
unsafe {
let a0 = _mm_mul_ps(v0.m_vec128.simd, self.m_vec128.simd);
let a1 = _mm_mul_ps(v1.m_vec128.simd, self.m_vec128.simd);
let mut a2 = _mm_mul_ps(v2.m_vec128.simd, self.m_vec128.simd);
let b0 = _mm_unpacklo_ps(a0, a1);
let b1 = _mm_unpackhi_ps(a0, a1);
let b2 = _mm_unpacklo_ps(a2, _mm_setzero_ps());
let mut r = _mm_movelh_ps(b0, b2);
r = _mm_add_ps(r, _mm_movehl_ps(b2, b0));
a2 = _mm_and_ps(a2, btv_xyz_maskf!());
r = _mm_add_ps(r, bt_castd_to128f!(_mm_move_sd( bt_castf_to128d!(a2), bt_castf_to128d!(b1))));
return BtVector3::new_simd(r);
}
}
}
#[inline(always)]
pub fn bt_dot(v1: &BtVector3, v2: &BtVector3) -> BtScalar { return v1.dot(v2); }
#[inline(always)]
pub fn bt_distance2(v1: &BtVector3, v2: &BtVector3) -> BtScalar { return v1.distance2(v2); }
#[inline(always)]
pub fn bt_distance(v1: &BtVector3, v2: &BtVector3) -> BtScalar { return v1.distance(v2); }
#[inline(always)]
pub fn bt_angle(v1: &BtVector3, v2: &BtVector3) -> BtScalar { return v1.angle(v2); }
#[inline(always)]
pub fn bt_cross(v1: &BtVector3, v2: &BtVector3) -> BtVector3 { return v1.cross(v2); }
#[inline(always)]
pub fn bt_triple(v1: &BtVector3, v2: &BtVector3, v3: &BtVector3) -> BtScalar {
return v1.triple(v2, v3);
}
#[inline(always)]
pub fn lerp(v1: &BtVector3, v2: &BtVector3, t: &BtScalar) -> BtVector3 { return v1.lerp(v2, t); }
#[test]
pub fn test() {
let mut a = BtVector3::new_default();
let b: BtScalar = 10.0;
a /= b;
a.set_value(10.0, 20.0, 4.0);
unsafe {
assert_eq!(a.m_vec128.array[0], 10.0);
}
}