use glam_det::nums::num_traits::*;
use glam_det::nums::{f32x4, u32x4};
use glam_det::{Cross, Dot, Mat3x4, UnitQuat, UnitQuatx4, Vec3, Vec3x4};
use crate::collision_tasks::{ShapeTester, ShapeWideTester};
use crate::convex_contact_manifold::{Convex4ContactManifoldWide, ConvexContactManifold};
use crate::shapes::{Cuboid, CuboidWide, InfinitePlaneWide};
use crate::traits::{ContactContext, ContactManifoldWide, CreateShapeWide, PairTest, PairWideTest};
use crate::{InfinitePlane, ShapeContainer};
impl PairWideTest<CuboidWide, InfinitePlaneWide> for ShapeWideTester {
#[inline]
fn should_reset_manifold_before_test() -> bool {
false
}
#[inline]
fn test(
a: &CuboidWide,
_b: &InfinitePlaneWide,
contact_context: &ContactContext,
manifold: &mut Convex4ContactManifoldWide,
) {
let ra = Mat3x4::from_quat(*contact_context.orientation_a);
let rb = Mat3x4::from_quat(*contact_context.orientation_b);
let world_to_plane = rb.transpose();
let box_to_plane = world_to_plane * ra;
let box_center_in_plane = world_to_plane * (-*contact_context.offset_b);
let box_center_depth = box_center_in_plane.y;
let vertices = [
Vec3x4::new(a.half_length.x, a.half_length.y, a.half_length.z),
Vec3x4::new(a.half_length.x, a.half_length.y, -a.half_length.z),
Vec3x4::new(a.half_length.x, -a.half_length.y, a.half_length.z),
Vec3x4::new(a.half_length.x, -a.half_length.y, -a.half_length.z),
Vec3x4::new(-a.half_length.x, a.half_length.y, a.half_length.z),
Vec3x4::new(-a.half_length.x, a.half_length.y, -a.half_length.z),
Vec3x4::new(-a.half_length.x, -a.half_length.y, a.half_length.z),
Vec3x4::new(-a.half_length.x, -a.half_length.y, -a.half_length.z),
];
let plane_normal_in_cube = box_to_plane.transpose().y_axis;
let dx = plane_normal_in_cube.x * a.half_length.x;
let dy = plane_normal_in_cube.y * a.half_length.y;
let dz = plane_normal_in_cube.z * a.half_length.z;
let active_lanes =
u32x4::splat(contact_context.pair_count as u32).gt(u32x4::from([0, 1, 2, 3]));
let depths = [
(dx + dy + dz + box_center_depth).select(active_lanes, f32x4::MAX),
(dx + dy - dz + box_center_depth).select(active_lanes, f32x4::MAX),
(dx - dy + dz + box_center_depth).select(active_lanes, f32x4::MAX),
(dx - dy - dz + box_center_depth).select(active_lanes, f32x4::MAX),
(-dx + dy + dz + box_center_depth).select(active_lanes, f32x4::MAX),
(-dx + dy - dz + box_center_depth).select(active_lanes, f32x4::MAX),
(-dx - dy + dz + box_center_depth).select(active_lanes, f32x4::MAX),
(-dx - dy - dz + box_center_depth).select(active_lanes, f32x4::MAX),
];
manifold.feature_id[0] = u32x4::ZERO;
manifold.feature_id[1] = u32x4::ONE;
manifold.feature_id[2] = u32x4::const_splat(2);
manifold.feature_id[3] = u32x4::const_splat(3);
let mut contact_counts = u32x4::ZERO;
let mut candidates = [(f32x4::MAX, Vec3x4::default()); 8];
for i in 0..8 {
let depth_lt_margin = depths[i].lt(contact_context.speculative_margin);
candidates[i].0 = -depths[i];
candidates[i].1 = contact_context.orientation_a * vertices[i];
contact_counts = (contact_counts + u32x4::ONE).select(depth_lt_margin, contact_counts);
}
let no_contact = contact_counts == u32x4::ZERO;
if no_contact {
manifold.reset(4);
return;
}
let normal = rb * InfinitePlaneWide::NORMAL.as_vec3x4();
manifold.normal = normal.as_unit_vec3x4_unchecked();
manifold.contact_exists[0] = contact_counts.ge(u32x4::ONE);
manifold.contact_exists[1] = contact_counts.ge(u32x4::const_splat(2));
manifold.contact_exists[2] = contact_counts.ge(u32x4::const_splat(3));
manifold.contact_exists[3] = contact_counts.ge(u32x4::const_splat(4));
let mut c0_i = u32x4::const_splat(8);
let mut c1_i = u32x4::const_splat(8);
let mut c2_i = u32x4::const_splat(8);
let mut c3_i = u32x4::const_splat(8);
manifold.depth[0] = f32x4::MIN;
candidates.iter().enumerate().for_each(
#[inline]
|(i, candidate)| {
let dx4 = candidate.0;
let d_gt_margin = dx4.gt(-contact_context.speculative_margin);
let d_gt = dx4.gt(manifold.depth[0]);
let update_c0 = d_gt_margin & d_gt;
manifold.depth[0] = dx4.select(update_c0, manifold.depth[0]);
manifold.offset_a[0] =
Vec3x4::lane_select(update_c0, candidate.1, manifold.offset_a[0]);
c0_i = u32x4::const_splat(i as u32).select(update_c0, c0_i);
},
);
let mut max_c0c1 = f32x4::ZERO;
let mut c1_d = f32x4::default();
let mut contact1 = Vec3x4::default();
candidates.iter().enumerate().for_each(
#[inline]
|(i, candidate)| {
let ix4 = u32x4::const_splat(i as u32);
let ne_c0 = ix4.ne(c0_i);
let dx4 = candidate.0;
let d_gt_margin = dx4.gt(-contact_context.speculative_margin);
let dist = candidate.1.distance_squared(manifold.offset_a[0]);
let dist_gt_max_c0c1 = dist.gt(max_c0c1);
let update_c1 = ne_c0 & d_gt_margin & dist_gt_max_c0c1;
max_c0c1 = dist.select(update_c1, max_c0c1);
contact1 = Vec3x4::lane_select(update_c1, candidate.1, contact1);
c1_d = dx4.select(update_c1, c1_d);
c1_i = ix4.select(update_c1, c1_i);
},
);
let mut max_c2_seg = f32x4::MIN;
let mut min_c3_seg = f32x4::MAX;
let mut contact2 = Vec3x4::default();
let mut contact3 = Vec3x4::default();
let mut c2_d = f32x4::default();
let mut c3_d = f32x4::default();
let seg = contact1 - manifold.offset_a[0];
let mut seg_norm = seg.cross(normal).normalize_or_zero();
let norm_eq_zero = seg_norm.cmpeq(Vec3x4::ZERO);
seg_norm = Vec3x4::select(norm_eq_zero, normal, seg_norm);
candidates.iter().enumerate().for_each(
#[inline]
|(i, candidate)| {
let dx4 = candidate.0;
let ix4 = u32x4::const_splat(i as u32);
let d_gt_margin = dx4.gt(-contact_context.speculative_margin);
let p_ne_c0 = ix4.ne(c0_i);
let p_ne_c1 = ix4.ne(c1_i);
let c0p = candidate.1 - manifold.offset_a[0];
let dist = c0p.dot(seg_norm);
let dist_gt_max_c2 = dist.gt(max_c2_seg);
let dist_lt_min_c3 = dist.lt(min_c3_seg);
let update_c2 =
p_ne_c0 & p_ne_c1 & d_gt_margin & dist_gt_max_c2 & manifold.contact_exists[2];
let update_c3 =
p_ne_c0 & p_ne_c1 & d_gt_margin & dist_lt_min_c3 & manifold.contact_exists[3];
max_c2_seg = dist.select(update_c2, max_c2_seg);
min_c3_seg = dist.select(update_c3, min_c3_seg);
contact2 = Vec3x4::lane_select(update_c2, candidate.1, contact2);
contact3 = Vec3x4::lane_select(update_c3, candidate.1, contact3);
c2_d = dx4.select(update_c2, c2_d);
c3_d = dx4.select(update_c3, c3_d);
c2_i = ix4.select(update_c2, c2_i);
c3_i = ix4.select(update_c3, c3_i);
},
);
let mut closest_1_d = f32x4::MAX;
let mut closest_2_d = f32x4::MAX;
let mut closest_3_d = f32x4::MAX;
manifold.offset_a[1] = contact1;
manifold.offset_a[2] = contact2;
manifold.offset_a[3] = contact3;
manifold.depth[1] = c1_d;
manifold.depth[2] = c2_d;
manifold.depth[3] = c3_d;
candidates.iter().enumerate().for_each(
#[inline]
|(i, candidate)| {
let dx4 = candidate.0;
let ix4 = u32x4::const_splat(i as u32);
let p_ne_c0 = ix4.ne(c0_i);
let p_ne_c1 = ix4.ne(c1_i);
let p_ne_c2 = ix4.ne(c2_i);
let p_ne_c3 = ix4.ne(c3_i);
let p_ne = p_ne_c0 & p_ne_c1 & p_ne_c2 & p_ne_c3;
let d_gt_margin = dx4.gt(-contact_context.speculative_margin);
let dist_1 = candidate.1.distance_squared(contact1);
let dist_2 = candidate.1.distance_squared(contact2);
let dist_3 = candidate.1.distance_squared(contact3);
let dist1_is_closest = dist_1.le(dist_2) & dist_1.le(dist_3);
let dist2_is_closest = dist_2.le(dist_1) & dist_2.le(dist_3);
let dist3_is_closest = dist_3.le(dist_1) & dist_3.le(dist_2);
let d_gt_cc1d = dx4.gt(manifold.depth[1]);
let d_gt_cc2d = dx4.gt(manifold.depth[2]);
let d_gt_cc3d = dx4.gt(manifold.depth[3]);
let change_1 = p_ne & d_gt_margin & d_gt_cc1d & dist1_is_closest;
closest_1_d = dist_1.select(change_1, closest_1_d);
manifold.offset_a[1] =
Vec3x4::lane_select(change_1, candidate.1, manifold.offset_a[1]);
manifold.depth[1] = dx4.select(change_1, manifold.depth[1]);
let change_2 = p_ne & d_gt_margin & d_gt_cc2d & dist2_is_closest;
closest_2_d = dist_2.select(change_2, closest_2_d);
manifold.offset_a[2] =
Vec3x4::lane_select(change_2, candidate.1, manifold.offset_a[2]);
manifold.depth[2] = dx4.select(change_2, manifold.depth[2]);
let change_3 = p_ne & d_gt_margin & d_gt_cc3d & dist3_is_closest;
closest_3_d = dist_3.select(change_3, closest_3_d);
manifold.offset_a[3] =
Vec3x4::lane_select(change_3, candidate.1, manifold.offset_a[3]);
manifold.depth[3] = dx4.select(change_3, manifold.depth[3]);
},
);
}
}
impl_pair_narrowphase!(Cuboid, InfinitePlane, CuboidWide, InfinitePlaneWide, 4);