#![allow(clippy::needless_range_loop)]
#![allow(clippy::should_implement_trait)]
use crate::body::{body_flags, BodyState, IDENTITY_BODY_STATE};
use crate::core::NULL_INDEX;
use crate::math_functions::Vec2;
pub const SIMD_WIDTH: usize = 4;
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct FloatW(pub [f32; SIMD_WIDTH]);
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct MaskW(pub [bool; SIMD_WIDTH]);
impl MaskW {
#[inline]
pub fn or(self, other: MaskW) -> MaskW {
let mut r = [false; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] || other.0[i];
}
MaskW(r)
}
}
impl FloatW {
#[inline]
pub fn zero() -> FloatW {
FloatW([0.0; SIMD_WIDTH])
}
#[inline]
pub fn splat(scalar: f32) -> FloatW {
FloatW([scalar; SIMD_WIDTH])
}
#[inline]
pub fn add(self, b: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] + b.0[i];
}
FloatW(r)
}
#[inline]
pub fn sub(self, b: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] - b.0[i];
}
FloatW(r)
}
#[inline]
pub fn mul(self, b: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] * b.0[i];
}
FloatW(r)
}
#[inline]
pub fn mul_add(self, b: FloatW, c: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] + b.0[i] * c.0[i];
}
FloatW(r)
}
#[inline]
pub fn mul_sub(self, b: FloatW, c: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] - b.0[i] * c.0[i];
}
FloatW(r)
}
#[inline]
pub fn min(self, b: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = if self.0[i] < b.0[i] {
self.0[i]
} else {
b.0[i]
};
}
FloatW(r)
}
#[inline]
pub fn max(self, b: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = if self.0[i] > b.0[i] {
self.0[i]
} else {
b.0[i]
};
}
FloatW(r)
}
#[inline]
pub fn sym_clamp(self, b: FloatW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
let nb = -b.0[i];
let m = if self.0[i] < b.0[i] {
self.0[i]
} else {
b.0[i]
};
r[i] = if nb > m { nb } else { m };
}
FloatW(r)
}
#[inline]
pub fn greater_than(self, b: FloatW) -> MaskW {
let mut r = [false; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] > b.0[i];
}
MaskW(r)
}
#[inline]
pub fn equals(self, b: FloatW) -> MaskW {
let mut r = [false; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = self.0[i] == b.0[i];
}
MaskW(r)
}
#[inline]
pub fn all_zero(self) -> bool {
self.0[0] == 0.0 && self.0[1] == 0.0 && self.0[2] == 0.0 && self.0[3] == 0.0
}
#[inline]
pub fn blend(a: FloatW, b: FloatW, mask: MaskW) -> FloatW {
let mut r = [0.0; SIMD_WIDTH];
for i in 0..SIMD_WIDTH {
r[i] = if mask.0[i] { b.0[i] } else { a.0[i] };
}
FloatW(r)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Vec2W {
pub x: FloatW,
pub y: FloatW,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct RotW {
pub c: FloatW,
pub s: FloatW,
}
#[inline]
pub fn dot_w(a: Vec2W, b: Vec2W) -> FloatW {
a.x.mul(b.x).add(a.y.mul(b.y))
}
#[inline]
pub fn cross_w(a: Vec2W, b: Vec2W) -> FloatW {
a.x.mul(b.y).sub(a.y.mul(b.x))
}
#[inline]
pub fn rotate_vector_w(q: RotW, v: Vec2W) -> Vec2W {
Vec2W {
x: q.c.mul(v.x).sub(q.s.mul(v.y)),
y: q.s.mul(v.x).add(q.c.mul(v.y)),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct BodyStateW {
pub v: Vec2W,
pub w: FloatW,
pub flags: FloatW,
pub dp: Vec2W,
pub dq: RotW,
}
#[inline]
pub fn gather_bodies(states: &[BodyState], indices: &[i32; SIMD_WIDTH]) -> BodyStateW {
let mut out = BodyStateW::default();
for lane in 0..SIMD_WIDTH {
let i = indices[lane] - 1;
let s = if i == NULL_INDEX {
IDENTITY_BODY_STATE
} else {
states[i as usize]
};
out.v.x.0[lane] = s.linear_velocity.x;
out.v.y.0[lane] = s.linear_velocity.y;
out.w.0[lane] = s.angular_velocity;
out.flags.0[lane] = s.flags as f32;
out.dp.x.0[lane] = s.delta_position.x;
out.dp.y.0[lane] = s.delta_position.y;
out.dq.c.0[lane] = s.delta_rotation.c;
out.dq.s.0[lane] = s.delta_rotation.s;
}
out
}
#[inline]
pub fn scatter_bodies(states: &mut [BodyState], indices: &[i32; SIMD_WIDTH], body: &BodyStateW) {
for lane in 0..SIMD_WIDTH {
let i = indices[lane] - 1;
if i == NULL_INDEX {
continue;
}
let state = &mut states[i as usize];
if state.flags & body_flags::DYNAMIC_FLAG != 0 {
state.linear_velocity = Vec2 {
x: body.v.x.0[lane],
y: body.v.y.0[lane],
};
state.angular_velocity = body.w.0[lane];
}
}
}