use glam_det::nums::num_traits::*;
use glam_det::nums::{f32x4, u32x4};
use glam_det::{Cross, Dot, Mat3x4, UnitQuat, UnitQuatx4, UnitVec3x4, Vec3, Vec3x4};
use crate::{
ContactContextTester as ContactContext, ContactManifoldWide, Convex4ContactManifoldWide,
ConvexContactManifold, CreateShapeWide, PairTest, PairWideTest, ShapeContainer, ShapeTester,
ShapeWideTester, Sphere, SphereWide, Triangle, TriangleWide,
};
impl PairWideTest<SphereWide, TriangleWide> for ShapeWideTester {
#[inline]
fn should_reset_manifold_before_test() -> bool {
false
}
#[inline]
fn test(
a: &SphereWide,
local_triangle: &TriangleWide,
contact_context: &ContactContext,
manifold: &mut Convex4ContactManifoldWide,
) {
let rotation_b = Mat3x4::from_quat(*contact_context.orientation_b);
let local_offset_b = rotation_b.transpose() * *contact_context.offset_b;
let speculative_margin = contact_context.speculative_margin;
let ab = local_triangle.b - local_triangle.a;
let ac = local_triangle.c - local_triangle.a;
let pa = (local_triangle.a + local_offset_b).as_vec3x4();
let mut local_triangle_normal = Vec3x4::cross(ab, ac);
let triangle_normal_length = local_triangle_normal.length();
let inverse_triangle_normal_length = triangle_normal_length.recip();
local_triangle_normal *= inverse_triangle_normal_length;
let pa_x_ab = Vec3x4::cross(pa, ab);
let ac_x_pa = Vec3x4::cross(ac, pa);
let edge_plane_test_ab = Vec3x4::dot(pa_x_ab, local_triangle_normal);
let edge_plane_test_ac = Vec3x4::dot(ac_x_pa, local_triangle_normal);
let edge_plane_test_bc =
f32x4::ONE - (edge_plane_test_ab + edge_plane_test_ac) * inverse_triangle_normal_length;
let outside_ab = edge_plane_test_ab.lt(f32x4::ZERO);
let outside_bc = edge_plane_test_bc.lt(f32x4::ZERO);
let outside_ac = edge_plane_test_ac.lt(f32x4::ZERO);
let outside_any_edge = outside_ab | outside_bc | outside_ac;
let active_lanes =
!(u32x4::splat(contact_context.pair_count as u32).le(u32x4::from([0, 1, 2, 3])));
let pa_n = Vec3x4::dot(local_triangle_normal, pa);
let offset_to_plane = pa_n * local_triangle_normal;
let point_on_face = offset_to_plane - local_offset_b;
let local_closest_on_triangle = point_on_face;
manifold.feature_id[0] = u32x4::select(u32x4::ZERO, outside_any_edge, u32x4::ONE);
let offset_a = (rotation_b * local_closest_on_triangle) + *contact_context.offset_b;
let distance = offset_a.length();
let normal_scale = -distance.recip();
let world_normal = (offset_a * normal_scale).as_unit_vec3x4_unchecked();
let face_normal_dot_local_normal =
Vec3x4::dot(rotation_b * local_triangle_normal, world_normal);
let backface_normal = -world_normal;
let backface_depth = distance + a.radius;
let is_backface = face_normal_dot_local_normal.gt(f32x4::ZERO);
manifold.normal = UnitVec3x4::lane_select(is_backface, backface_normal, world_normal);
manifold.depth[0] = f32x4::select(backface_depth, is_backface, a.radius - distance);
manifold.offset_a[0] = offset_a;
manifold.contact_exists[0] = !outside_any_edge
& active_lanes
& distance.gt(f32x4::ZERO)
& manifold.depth[0].ge(-speculative_margin);
}
}
impl_pair_narrowphase!(Sphere, Triangle, SphereWide, TriangleWide, 1);