pub mod vector_types;
pub use vector_types::Simd;
#[allow(non_camel_case_types)]
pub type i8x2 = Simd<i8, 2, 2>;
#[allow(non_camel_case_types)]
pub type i8x3 = Simd<i8, 4, 3>;
#[allow(non_camel_case_types)]
pub type i8x4 = Simd<i8, 4, 4>;
#[allow(non_camel_case_types)]
pub type u8x2 = Simd<u8, 2, 2>;
#[allow(non_camel_case_types)]
pub type u8x3 = Simd<u8, 4, 3>;
#[allow(non_camel_case_types)]
pub type u8x4 = Simd<u8, 4, 4>;
#[allow(non_camel_case_types)]
pub type i16x2 = Simd<i16, 2, 2>;
#[allow(non_camel_case_types)]
pub type i16x3 = Simd<i16, 4, 3>;
#[allow(non_camel_case_types)]
pub type i16x4 = Simd<i16, 4, 4>;
#[allow(non_camel_case_types)]
pub type u16x2 = Simd<u16, 2, 2>;
#[allow(non_camel_case_types)]
pub type u16x3 = Simd<u16, 4, 3>;
#[allow(non_camel_case_types)]
pub type u16x4 = Simd<u16, 4, 4>;
#[cfg(not(target_arch = "aarch64"))]
#[allow(non_camel_case_types)]
pub type f32x2 = Simd<f32, 2, 2>;
#[cfg(target_arch = "aarch64")]
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct f32x2(pub std::arch::aarch64::float32x2_t);
#[cfg(target_arch = "aarch64")]
impl PartialEq for f32x2 {
fn eq(&self, other: &Self) -> bool {
unsafe {
let cmp = std::arch::aarch64::vceq_f32(self.0, other.0);
let bits: u64 = std::mem::transmute(cmp);
bits == u64::MAX
}
}
}
#[cfg(target_arch = "aarch64")]
impl PartialEq<[f32; 2]> for f32x2 {
fn eq(&self, other: &[f32; 2]) -> bool {
self == &Self::load(other)
}
}
#[cfg(target_arch = "aarch64")]
impl Default for f32x2 {
fn default() -> Self {
Self::load(&[0.0; 2])
}
}
#[cfg(target_arch = "aarch64")]
impl f32x2 {
pub fn x(&self) -> f32 {
unsafe { std::arch::aarch64::vget_lane_f32::<0>(self.0) }
}
pub fn y(&self) -> f32 {
unsafe { std::arch::aarch64::vget_lane_f32::<1>(self.0) }
}
pub fn r(&self) -> f32 {
unsafe { std::arch::aarch64::vget_lane_f32::<0>(self.0) }
}
pub fn g(&self) -> f32 {
unsafe { std::arch::aarch64::vget_lane_f32::<1>(self.0) }
}
pub fn set_x(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vset_lane_f32::<0>(val, self.0) }
}
pub fn set_y(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vset_lane_f32::<1>(val, self.0) }
}
pub fn set_r(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vset_lane_f32::<0>(val, self.0) }
}
pub fn set_g(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vset_lane_f32::<1>(val, self.0) }
}
#[inline]
pub fn with_xy(x: f32, y: f32) -> Self {
Self::load(&[x, y])
}
pub fn load(vals: &[f32; 2]) -> Self {
Self(unsafe { std::arch::aarch64::vld1_f32(vals.as_ptr()) })
}
pub fn splat(val: f32) -> Self {
Self(unsafe { std::arch::aarch64::vdup_n_f32(val) })
}
pub fn to_bits(&self) -> u64 {
unsafe { std::mem::transmute(*self) }
}
}
#[cfg(target_arch = "aarch64")]
impl std::ops::Add for f32x2 {
type Output = f32x2;
fn add(self, rhs: Self) -> Self::Output {
unsafe { Self(std::arch::aarch64::vadd_f32(self.0, rhs.0)) }
}
}
#[cfg(target_arch = "aarch64")]
impl std::ops::Mul for f32x2 {
type Output = f32x2;
fn mul(self, rhs: Self) -> Self::Output {
unsafe { Self(std::arch::aarch64::vmul_f32(self.0, rhs.0)) }
}
}
#[cfg(target_arch = "aarch64")]
impl std::ops::Sub for f32x2 {
type Output = f32x2;
fn sub(self, rhs: Self) -> Self::Output {
unsafe { Self(std::arch::aarch64::vsub_f32(self.0, rhs.0)) }
}
}
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub type f16x2 = Simd<half::f16, 2, 2>;
#[allow(non_camel_case_types)]
pub type f32x3 = Simd<f32, 4, 3>;
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub type f16x3 = Simd<half::f16, 4, 3>;
#[cfg(not(target_arch = "aarch64"))]
#[allow(non_camel_case_types)]
pub type f32x4 = Simd<f32, 4, 4>;
#[cfg(target_arch = "aarch64")]
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct f32x4(pub std::arch::aarch64::float32x4_t);
#[cfg(target_arch = "aarch64")]
impl PartialEq for f32x4 {
fn eq(&self, other: &Self) -> bool {
unsafe {
let cmp = std::arch::aarch64::vceqq_f32(self.0, other.0);
let bits: u128 = std::mem::transmute(cmp);
bits == u128::MAX
}
}
}
#[cfg(target_arch = "aarch64")]
impl PartialEq<[f32; 4]> for f32x4 {
fn eq(&self, other: &[f32; 4]) -> bool {
self == &Self::load(other)
}
}
#[cfg(target_arch = "aarch64")]
impl Default for f32x4 {
fn default() -> Self {
Self::load(&[0.0; 4])
}
}
#[cfg(target_arch = "aarch64")]
impl f32x4 {
pub fn x(&self) -> f32 {
unsafe { std::arch::aarch64::vgetq_lane_f32::<0>(self.0) }
}
pub fn y(&self) -> f32 {
unsafe { std::arch::aarch64::vgetq_lane_f32::<1>(self.0) }
}
pub fn z(&self) -> f32 {
unsafe { std::arch::aarch64::vgetq_lane_f32::<2>(self.0) }
}
pub fn w(&self) -> f32 {
unsafe { std::arch::aarch64::vgetq_lane_f32::<3>(self.0) }
}
pub fn set_x(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vsetq_lane_f32::<0>(val, self.0) }
}
pub fn set_y(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vsetq_lane_f32::<1>(val, self.0) }
}
pub fn set_z(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vsetq_lane_f32::<2>(val, self.0) }
}
pub fn set_w(&mut self, val: f32) {
self.0 = unsafe { std::arch::aarch64::vsetq_lane_f32::<3>(val, self.0) }
}
#[inline]
pub fn with_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self {
Self::load(&[x, y, z, w])
}
#[inline]
pub fn with_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
Self::load(&[r, g, b, a])
}
pub fn load(vals: &[f32; 4]) -> Self {
Self(unsafe { std::arch::aarch64::vld1q_f32(vals.as_ptr()) })
}
pub fn splat(val: f32) -> Self {
Self(unsafe { std::arch::aarch64::vdupq_n_f32(val) })
}
pub fn to_bits(&self) -> u128 {
unsafe { std::mem::transmute(*self) }
}
}
#[cfg(target_arch = "aarch64")]
impl std::ops::Add for f32x4 {
type Output = f32x4;
fn add(self, rhs: Self) -> Self::Output {
unsafe { Self(std::arch::aarch64::vaddq_f32(self.0, rhs.0)) }
}
}
#[cfg(target_arch = "aarch64")]
impl std::ops::Mul for f32x4 {
type Output = f32x4;
fn mul(self, rhs: Self) -> Self::Output {
unsafe { Self(std::arch::aarch64::vmulq_f32(self.0, rhs.0)) }
}
}
#[cfg(target_arch = "aarch64")]
impl std::ops::Sub for f32x4 {
type Output = f32x4;
fn sub(self, rhs: Self) -> Self::Output {
unsafe { Self(std::arch::aarch64::vsubq_f32(self.0, rhs.0)) }
}
}
#[allow(non_camel_case_types)]
pub type f64x4 = Simd<f64, 4, 4>;
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub type f16x4 = Simd<half::f16, 4, 4>;
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub struct f16x2x2(pub [f16x2; 2]);
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub struct f16x3x2(pub [f16x2; 3]);
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub struct f16x4x2(pub [f16x2; 4]);
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub struct f16x2x3(pub [f16x3; 2]);
#[cfg(feature = "half")]
#[allow(non_camel_case_types)]
pub struct f16x3x3(pub [f16x3; 3]);
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32x2x2(pub [f32x2; 2]);
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32x3x2(pub [f32x2; 3]);
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32x4x2(pub [f32x2; 4]);
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32x2x3(pub [f32x3; 2]);
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32x3x3(pub [f32x3; 3]);
impl f32x3x3 {
pub fn diagonal(v: f32x3) -> Self {
Self([
f32x3::with_xyz_f32(v.x(), 0.0, 0.0),
f32x3::with_xyz_f32(0.0, v.y(), 0.0),
f32x3::with_xyz_f32(0.0, 0.0, v.z()),
])
}
pub const fn identity() -> Self {
Self([
f32x3::with_xyz_f32(1.0, 0.0, 0.0),
f32x3::with_xyz_f32(0.0, 1.0, 0.0),
f32x3::with_xyz_f32(0.0, 0.0, 1.0),
])
}
pub const fn translate(tx: f32, ty: f32) -> Self {
Self([
f32x3::with_xyz_f32(1.0, 0.0, tx),
f32x3::with_xyz_f32(0.0, 1.0, ty),
f32x3::with_xyz_f32(0.0, 0.0, 1.0),
])
}
}
#[cfg(not(target_arch = "aarch64"))]
#[derive(Debug, Copy, Clone, PartialEq)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32x4x4(pub [f32x4; 4]);
#[cfg(target_arch = "aarch64")]
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32x4x4(pub std::arch::aarch64::float32x4x4_t);
#[cfg(target_arch = "aarch64")]
impl PartialEq for f32x4x4 {
fn eq(&self, other: &Self) -> bool {
unsafe {
let cmp0 = std::arch::aarch64::vceqq_f32(self.0.0, other.0.0);
let cmp1 = std::arch::aarch64::vceqq_f32(self.0.1, other.0.1);
let cmp2 = std::arch::aarch64::vceqq_f32(self.0.2, other.0.2);
let cmp3 = std::arch::aarch64::vceqq_f32(self.0.3, other.0.3);
let cmp0: u128 = std::mem::transmute(cmp0);
let cmp1: u128 = std::mem::transmute(cmp1);
let cmp2: u128 = std::mem::transmute(cmp2);
let cmp3: u128 = std::mem::transmute(cmp3);
cmp0 == u128::MAX && cmp1 == u128::MAX && cmp2 == u128::MAX && cmp3 == u128::MAX
}
}
}
impl f32x4x4 {
#[cfg(not(target_arch = "aarch64"))]
pub fn diagonal(v: f32x4) -> Self {
Self([
f32x4::with_xyzw(v.x(), 0.0, 0.0, 0.0),
f32x4::with_xyzw(0.0, v.y(), 0.0, 0.0),
f32x4::with_xyzw(0.0, 0.0, v.z(), 0.0),
f32x4::with_xyzw(0.0, 0.0, 0.0, v.w()),
])
}
#[cfg(target_arch = "aarch64")]
pub fn diagonal(v: f32x4) -> Self {
Self(std::arch::aarch64::float32x4x4_t(
f32x4::with_xyzw(v.x(), 0.0, 0.0, 0.0).0,
f32x4::with_xyzw(0.0, v.y(), 0.0, 0.0).0,
f32x4::with_xyzw(0.0, 0.0, v.z(), 0.0).0,
f32x4::with_xyzw(0.0, 0.0, 0.0, v.w()).0,
))
}
#[cfg(not(target_arch = "aarch64"))]
pub fn identity() -> Self {
Self([
f32x4::with_xyzw(1.0, 0.0, 0.0, 0.0),
f32x4::with_xyzw(0.0, 1.0, 0.0, 0.0),
f32x4::with_xyzw(0.0, 0.0, 1.0, 0.0),
f32x4::with_xyzw(0.0, 0.0, 0.0, 1.0),
])
}
#[cfg(target_arch = "aarch64")]
pub fn identity() -> Self {
Self(std::arch::aarch64::float32x4x4_t(
f32x4::with_xyzw(1.0, 0.0, 0.0, 0.0).0,
f32x4::with_xyzw(0.0, 1.0, 0.0, 0.0).0,
f32x4::with_xyzw(0.0, 0.0, 1.0, 0.0).0,
f32x4::with_xyzw(0.0, 0.0, 0.0, 1.0).0,
))
}
#[cfg(not(target_arch = "aarch64"))]
pub fn translate(tx: f32, ty: f32, tz: f32) -> Self {
Self([
f32x4::with_xyzw(1.0, 0.0, 0.0, 0.0),
f32x4::with_xyzw(0.0, 1.0, 0.0, 0.0),
f32x4::with_xyzw(0.0, 0.0, 1.0, 0.0),
f32x4::with_xyzw(tx, ty, tz, 1.0),
])
}
#[cfg(target_arch = "aarch64")]
pub fn translate(tx: f32, ty: f32, tz: f32) -> Self {
Self(std::arch::aarch64::float32x4x4_t(
f32x4::with_xyzw(1.0, 0.0, 0.0, 0.0).0,
f32x4::with_xyzw(0.0, 1.0, 0.0, 0.0).0,
f32x4::with_xyzw(0.0, 0.0, 1.0, 0.0).0,
f32x4::with_xyzw(tx, ty, tz, 1.0).0,
))
}
#[inline]
pub fn tx(&self) -> f32 {
self[3].x()
}
#[inline]
pub fn set_tx(&mut self, value: f32) {
self[3].set_x(value)
}
#[inline]
pub fn ty(&self) -> f32 {
self[3].y()
}
#[inline]
pub fn set_ty(&mut self, value: f32) {
self[3].set_y(value)
}
#[inline]
pub fn tz(&self) -> f32 {
self[3].z()
}
#[inline]
pub fn set_tz(&mut self, value: f32) {
self[3].set_z(value)
}
#[inline]
pub fn sx(&self) -> f32 {
self[0].x()
}
#[inline]
pub fn set_sx(&mut self, value: f32) {
self[0].set_x(value)
}
#[inline]
pub fn sy(&self) -> f32 {
self[1].y()
}
#[inline]
pub fn set_sy(&mut self, value: f32) {
self[1].set_y(value)
}
#[inline]
pub fn sz(&self) -> f32 {
self[2].z()
}
#[inline]
pub fn set_sz(&mut self, value: f32) {
self[2].set_z(value)
}
}
impl std::ops::Index<usize> for f32x4x4 {
type Output = f32x4;
#[cfg(not(target_arch = "aarch64"))]
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
#[cfg(target_arch = "aarch64")]
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => unsafe { std::mem::transmute(&self.0.0) },
1 => unsafe { std::mem::transmute(&self.0.1) },
2 => unsafe { std::mem::transmute(&self.0.2) },
3 => unsafe { std::mem::transmute(&self.0.3) },
_ => panic!(),
}
}
}
impl std::ops::IndexMut<usize> for f32x4x4 {
#[cfg(not(target_arch = "aarch64"))]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
#[cfg(target_arch = "aarch64")]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => unsafe { std::mem::transmute(&mut self.0.0) },
1 => unsafe { std::mem::transmute(&mut self.0.1) },
2 => unsafe { std::mem::transmute(&mut self.0.2) },
3 => unsafe { std::mem::transmute(&mut self.0.3) },
_ => panic!(),
}
}
}
#[cfg(feature = "half")]
#[derive(Debug, Copy, Clone, PartialEq)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f16x4x4(pub [f16x4; 4]);
#[cfg(feature = "half")]
impl f16x4x4 {
pub fn diagonal(v: f16x4) -> Self {
const Z: half::f16 = half::f16::ZERO;
Self([
f16x4::with_xyzw_f16(v.x(), Z, Z, Z),
f16x4::with_xyzw_f16(Z, v.y(), Z, Z),
f16x4::with_xyzw_f16(Z, Z, v.z(), Z),
f16x4::with_xyzw_f16(Z, Z, Z, v.w()),
])
}
pub const fn identity() -> Self {
const Z: half::f16 = half::f16::ZERO;
const O: half::f16 = half::f16::ONE;
Self([
f16x4::with_xyzw_f16(O, Z, Z, Z),
f16x4::with_xyzw_f16(Z, O, Z, Z),
f16x4::with_xyzw_f16(Z, Z, O, Z),
f16x4::with_xyzw_f16(Z, Z, Z, O),
])
}
pub const fn translate(tx: half::f16, ty: half::f16, tz: half::f16) -> Self {
const Z: half::f16 = half::f16::ZERO;
const O: half::f16 = half::f16::ONE;
Self([
f16x4::with_xyzw_f16(O, Z, Z, Z),
f16x4::with_xyzw_f16(Z, O, Z, Z),
f16x4::with_xyzw_f16(Z, Z, O, Z),
f16x4::with_xyzw_f16(tx, ty, tz, O),
])
}
#[inline]
pub fn tx(&self) -> half::f16 {
self[3].x()
}
#[inline]
pub fn set_tx(&mut self, value: half::f16) {
self[3].set_x(value)
}
#[inline]
pub fn ty(&self) -> half::f16 {
self[3].y()
}
#[inline]
pub fn set_ty(&mut self, value: half::f16) {
self[3].set_y(value)
}
#[inline]
pub fn tz(&self) -> half::f16 {
self[3].z()
}
#[inline]
pub fn set_tz(&mut self, value: half::f16) {
self[3].set_z(value)
}
#[inline]
pub fn sx(&self) -> half::f16 {
self[0].x()
}
#[inline]
pub fn set_sx(&mut self, value: half::f16) {
self[0].set_x(value)
}
#[inline]
pub fn sy(&self) -> half::f16 {
self[1].y()
}
#[inline]
pub fn set_sy(&mut self, value: half::f16) {
self[1].set_y(value)
}
#[inline]
pub fn sz(&self) -> half::f16 {
self[2].z()
}
#[inline]
pub fn set_sz(&mut self, value: half::f16) {
self[2].set_z(value)
}
}
#[cfg(feature = "half")]
impl std::ops::Index<usize> for f16x4x4 {
type Output = f16x4;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
#[cfg(feature = "half")]
impl std::ops::IndexMut<usize> for f16x4x4 {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
#[cfg(feature = "half")]
#[derive(Debug, Copy, Clone, PartialEq)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f16quat(pub f16x4);
#[derive(Debug, Copy, Clone, PartialEq)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f32quat(pub f32x4);
impl std::ops::Deref for f32quat {
type Target = f32x4;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for f32quat {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(target_arch = "aarch64")]
impl f32quat {
pub fn load(vals: &[f32; 4]) -> Self {
Self(f32x4::load(vals))
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct f64quat(pub f64x4);
#[cfg(feature = "half")]
impl f16quat {
#[inline]
pub fn with_angle(angle: half::f16, axis: f16x3) -> Self {
let half_angle = angle.to_f32() * 0.5;
let sin = half_angle.sin();
let x = sin * axis.x().to_f32();
let y = sin * axis.y().to_f32();
let z = sin * axis.z().to_f32();
let w = half_angle.cos();
Self(Simd([
half::f16::from_f32(x),
half::f16::from_f32(y),
half::f16::from_f32(z),
half::f16::from_f32(w),
]))
}
}
impl f32quat {
#[inline]
pub fn with_angle(angle: f32, axis: f32x3) -> Self {
let half_angle = angle * 0.5;
let sin = half_angle.sin();
Self(f32x4::load(&[
sin * axis.x(),
sin * axis.y(),
sin * axis.z(),
half_angle.cos(),
]))
}
}
pub mod packed {
use super::Simd;
#[allow(non_camel_case_types)]
pub type i8x2 = Simd<i8, 2, 2>;
#[allow(non_camel_case_types)]
pub type i8x4 = Simd<i8, 4, 4>;
#[allow(non_camel_case_types)]
pub type u8x2 = Simd<u8, 2, 2>;
#[allow(non_camel_case_types)]
pub type u8x4 = Simd<u8, 4, 4>;
#[allow(non_camel_case_types)]
pub type i16x2 = Simd<i16, 2, 2>;
#[allow(non_camel_case_types)]
pub type i16x4 = Simd<i16, 4, 4>;
#[allow(non_camel_case_types)]
pub type u16x2 = Simd<u16, 2, 2>;
#[allow(non_camel_case_types)]
pub type u16x4 = Simd<u16, 4, 4>;
#[allow(non_camel_case_types)]
pub type i32x2 = Simd<i32, 2, 2>;
#[allow(non_camel_case_types)]
pub type i32x4 = Simd<i32, 4, 4>;
#[allow(non_camel_case_types)]
pub type u32x2 = Simd<u32, 2, 2>;
#[allow(non_camel_case_types)]
pub type u32x4 = Simd<u32, 4, 4>;
#[allow(non_camel_case_types)]
pub type i64x2 = Simd<i64, 2, 2>;
#[allow(non_camel_case_types)]
pub type i64x4 = Simd<i64, 4, 4>;
#[allow(non_camel_case_types)]
pub type u64x2 = Simd<u64, 2, 2>;
#[allow(non_camel_case_types)]
pub type u64x4 = Simd<u64, 4, 4>;
#[allow(non_camel_case_types)]
pub type f32x2 = Simd<f32, 2, 2>;
#[allow(non_camel_case_types)]
pub type f32x4 = Simd<f32, 4, 4>;
}
#[cfg(test)]
mod tests {
use super::f32x2;
use super::f32x2x2;
#[test]
fn mul() {
let _x = f32x2x2([f32x2::with_xy(1.0, 0.0), f32x2::with_xy(1.0, 0.0)]);
let _y = f32x2x2([f32x2::with_xy(1.0, 0.0), f32x2::with_xy(1.0, 0.0)]);
}
#[cfg(feature = "half")]
#[test]
fn f16quat() {
use super::f16quat;
use super::f16x3;
let angle = half::f16::FRAC_PI_2;
let z = half::f16::ZERO;
let o = half::f16::ONE;
let axis = f16x3::with_xyz(z, z, o);
let quat = f16quat::with_angle(angle, axis);
let i = quat.0.x().to_f32();
let j = quat.0.y().to_f32();
let k = quat.0.z().to_f32();
let w = quat.0.w().to_f32();
assert_eq!([i, j, k, w], [0.0, 0.0, 0.70703125, 0.70751953]);
}
#[test]
fn f32quat() {
use std::f32;
use crate::simd::f32quat;
use crate::simd::f32x3;
let quat = f32quat::with_angle(f32::consts::FRAC_PI_2, f32x3::with_xyz(0.0, 0.0, 1.0));
assert_eq!(quat.0, [0.0, 0.0, 0.70710677, 0.70710677]);
}
}