use glam_det::nums::num_traits::*;
use glam_det::nums::{bool32x4, f32x4, u32x4};
use glam_det::{Isometry3, Point3, UnitVec3, UnitVec3x4, Vec3, Vec3x4};
use crate::collision_tasks::ConcaveManifold;
use crate::traits::{ContactManifold, ContactManifoldWide};
pub enum ManifoldRef<'a> {
Convex(&'a ConvexContactManifold),
Concave(&'a ConcaveManifold),
}
#[derive(Default)]
pub struct ConvexContactManifold {
pub offset_b: Vec3,
pub normal: UnitVec3,
pub count: usize,
pub contacts: [ConvexContact; 4],
}
impl ContactManifold for ConvexContactManifold {
const MAX_CONTACTS: usize = 4;
fn offset_b(&self) -> Vec3 {
self.offset_b
}
#[inline]
fn contact_count(&self) -> usize {
self.count
}
#[inline]
fn get_contact_normal(&self, _: usize) -> UnitVec3 {
self.normal
}
#[inline]
fn get_contact_offset_a(&self, contact_index: usize) -> Vec3 {
self.contacts[contact_index].offset_a
}
#[inline]
fn get_contact_depth(&self, contact_index: usize) -> f32 {
self.contacts[contact_index].depth
}
#[inline]
fn get_contact_feature_id(&self, contact_index: usize) -> u32 {
self.contacts[contact_index].feature_id
}
#[cfg(test)]
#[inline]
fn is_convex(&self) -> bool {
true
}
}
#[derive(Clone)]
pub struct ConvexContact {
pub offset_a: Vec3,
pub depth: f32,
pub feature_id: u32,
}
impl Default for ConvexContact {
#[inline]
fn default() -> Self {
Self {
offset_a: Vec3::default(),
depth: 0.0,
feature_id: 0,
}
}
}
#[derive(PartialEq, Debug)]
pub struct Convex4ContactManifoldWide {
pub offset_a: [Vec3x4; 4],
pub normal: UnitVec3x4,
pub depth: [f32x4; 4],
pub feature_id: [u32x4; 4],
pub contact_exists: [bool32x4; 4],
}
#[allow(dead_code)]
#[derive(PartialEq, Debug)]
pub struct Convex4ContactManifold {
pub offset_a: [Vec3; 4],
pub normal: UnitVec3,
pub depth: [f32; 4],
pub feature_id: [u32; 4],
pub contact_exists: [bool; 4],
}
impl ContactManifoldWide<ConvexContactManifold> for Convex4ContactManifoldWide {
#[inline]
fn apply_flip_mask(&mut self, count: usize, offset_b: &mut Vec3x4, flip_mask: &bool32x4) {
let flipped_offset = -*offset_b;
let flipped_normal = -self.normal;
let mut flipped_offset_a = [Vec3x4::ZERO; 4];
for (flipped_offset_a, (offset_a, depth)) in flipped_offset_a
.iter_mut()
.zip(self.offset_a.iter().zip(self.depth.iter()))
.take(count)
{
*flipped_offset_a = offset_a + self.normal * depth - *offset_b;
}
self.normal = UnitVec3x4::lane_select(*flip_mask, flipped_normal, self.normal);
*offset_b = Vec3x4::lane_select(*flip_mask, flipped_offset, *offset_b);
for (&flipped_offset_a, offset_a) in flipped_offset_a
.iter()
.zip(self.offset_a.iter_mut())
.take(count)
{
*offset_a = Vec3x4::lane_select(*flip_mask, flipped_offset_a, *offset_a);
}
}
#[inline]
fn get_manifold(
&self,
index: usize,
count: usize,
offset_wide: &Vec3x4,
result: &mut ConvexContactManifold,
) {
result.count = 0;
for i in 0..count {
if self.contact_exists[i].extract(index) {
let output_contact = &mut result.contacts[result.count];
output_contact.offset_a = self.offset_a[i].extract_lane(index);
output_contact.depth = self.depth[i].extract(index);
output_contact.feature_id = self.feature_id[i].extract(index);
result.count += 1;
}
}
if result.count > 0 {
result.offset_b = offset_wide.extract_lane(index);
result.normal = self.normal.extract_lane(index);
}
}
}
impl Default for Convex4ContactManifoldWide {
#[inline]
fn default() -> Self {
Self {
offset_a: Default::default(),
normal: UnitVec3x4::default(),
depth: [f32x4::ZERO; 4],
feature_id: [u32x4::ZERO; 4],
contact_exists: [bool32x4::FALSE; 4],
}
}
}
impl Convex4ContactManifoldWide {
#[inline]
pub fn reset(&mut self, count: usize) {
for i in 0..count {
self.contact_exists[i] = bool32x4::FALSE;
}
}
#[inline]
pub fn write_slot_with_candidate_scalar(
&mut self,
candidate: ManifoldCandidate,
i: usize,
contact_index: usize,
face_b: &Face,
transform_b: Isometry3,
) {
let offset_a =
face_b.origin + face_b.tangent_x * candidate.x + face_b.tangent_y * candidate.y;
let offset_a = transform_b.transform_point3(offset_a);
self.offset_a[contact_index].replace_lane(i, offset_a.as_vec3());
self.depth[contact_index].replace(i, candidate.depth);
self.feature_id[contact_index].replace(i, candidate.feature_id);
self.contact_exists[contact_index].replace(i, true);
}
}
#[derive(Copy, Clone, Debug)]
pub struct ManifoldCandidateWide {
pub x: f32x4,
pub y: f32x4,
pub depth: f32x4,
pub feature_id: u32x4,
}
#[derive(Copy, Clone, Debug, Default)]
pub struct ManifoldCandidate {
pub x: f32,
pub y: f32,
pub feature_id: u32,
pub depth: f32,
}
impl ManifoldCandidate {
#[inline]
#[must_use]
pub fn new(x: f32, y: f32, feature_id: u32) -> Self {
Self {
x,
y,
feature_id,
depth: 0.0,
}
}
}
pub struct Face {
pub origin: Point3,
pub tangent_x: UnitVec3,
pub tangent_y: UnitVec3,
}
impl Default for ManifoldCandidateWide {
#[inline]
fn default() -> Self {
Self {
x: f32x4::ZERO,
y: f32x4::ZERO,
depth: f32x4::ZERO,
feature_id: u32x4::ZERO,
}
}
}
#[derive(Default, Clone)]
pub struct OneContact {
pub offset_b: Vec3,
pub normal: UnitVec3,
pub offset_a: Vec3,
pub depth: f32,
pub feature_id: u32,
}
#[cfg(test)]
mod tests {
use approx_det::{AbsDiffEq, RelativeEq};
use crate::convex_contact_manifold::*;
impl AbsDiffEq for Convex4ContactManifoldWide {
type Epsilon = f32;
fn default_epsilon() -> Self::Epsilon {
f32::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.offset_a.iter().zip(other.offset_a.iter()).all(
#[inline]
|(a, b)| abs_diff_eq_vec3x4(a, b, epsilon),
) && abs_diff_eq_uint_vec3x4(&self.normal, &other.normal, epsilon)
&& self.depth.iter().zip(other.depth.iter()).all(
#[inline]
|(&a, b)| a.abs_diff_eq(b, epsilon),
)
&& self.feature_id.iter().zip(other.feature_id.iter()).all(
#[inline]
|(a, b)| a.eq(b).all(),
)
&& self
.contact_exists
.iter()
.zip(other.contact_exists.iter())
.all(
#[inline]
|(&a, b)| a.eq(b).all(),
)
}
}
impl RelativeEq for Convex4ContactManifoldWide {
fn default_max_relative() -> Self::Epsilon {
f32::default_max_relative()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.offset_a.iter().zip(other.offset_a.iter()).all(
#[inline]
|(a, b)| relative_eq_vec3x4(a, b, epsilon, max_relative),
) && relative_eq_uint_vec3x4(&self.normal, &other.normal, epsilon, max_relative)
&& self.depth.iter().zip(other.depth.iter()).all(
#[inline]
|(&a, b)| a.relative_eq(b, epsilon, max_relative).all(),
)
&& self.feature_id.iter().zip(other.feature_id.iter()).all(
#[inline]
|(a, b)| a.eq(b).all(),
)
&& self
.contact_exists
.iter()
.zip(other.contact_exists.iter())
.all(
#[inline]
|(a, b)| a.eq(b).all(),
)
}
}
fn relative_eq_vec3x4(left: &Vec3x4, right: &Vec3x4, epsilon: f32, max_relative: f32) -> bool {
left.x.relative_eq(&right.x, epsilon, max_relative)
&& left.y.relative_eq(&right.y, epsilon, max_relative)
&& left.z.relative_eq(&right.z, epsilon, max_relative)
}
fn abs_diff_eq_vec3x4(left: &Vec3x4, right: &Vec3x4, epsilon: f32) -> bool {
left.x.abs_diff_eq(&right.x, epsilon)
&& left.y.abs_diff_eq(&right.y, epsilon)
&& left.z.abs_diff_eq(&right.z, epsilon)
}
fn relative_eq_uint_vec3x4(
left: &UnitVec3x4,
right: &UnitVec3x4,
epsilon: f32,
max_relative: f32,
) -> bool {
left.x.relative_eq(&right.x, epsilon, max_relative)
&& left.y.relative_eq(&right.y, epsilon, max_relative)
&& left.z.relative_eq(&right.z, epsilon, max_relative)
}
fn abs_diff_eq_uint_vec3x4(left: &UnitVec3x4, right: &UnitVec3x4, epsilon: f32) -> bool {
left.x.abs_diff_eq(&right.x, epsilon)
&& left.y.abs_diff_eq(&right.y, epsilon)
&& left.z.abs_diff_eq(&right.z, epsilon)
}
}