use glam_det::nums::*;
use glam_det::{Dot, Mat3x4, UnitQuat, UnitQuatx4, UnitVec3x4, Vec3, Vec3x4};
use crate::collision_tasks::cuboid_cuboid_tester_helper::{
calculate_separating_axis, edges_of_face_b_clip_face_a, transform_candidate_to_manifold,
vertices_of_face_a_clip_face_b, Candidates, CuboidFace, CuboidFaceInitConfig, EdgeClipContext,
FacePairInfo, VertexClipContext, LOCAL_X_ID, LOCAL_Y_ID, LOCAL_Z_ID, MAX_U32X4, THREE_U32X4,
};
use crate::collision_tasks::traits::TransformWide;
use crate::collision_tasks::{ShapeTester, ShapeWideTester};
use crate::convex_contact_manifold::Convex4ContactManifoldWide;
use crate::shapes::CuboidWide;
use crate::traits::{ContactContext, ContactManifoldWide, CreateShapeWide, PairTest, PairWideTest};
use crate::{ConvexContactManifold, Cuboid, ShapeContainer};
impl PairWideTest<CuboidWide, CuboidWide> for ShapeWideTester {
#[inline]
fn should_reset_manifold_before_test() -> bool {
false
}
#[inline]
fn test(
a: &CuboidWide,
b: &CuboidWide,
contact_context: &ContactContext,
manifold: &mut Convex4ContactManifoldWide,
) {
let matrix_a = Mat3x4::from_quat(*contact_context.orientation_a);
let matrix_b = Mat3x4::from_quat(*contact_context.orientation_b);
let matrix_a_transpose = matrix_a.transpose();
let rotation_from_b_2_a_localspace = matrix_a_transpose * matrix_b;
let offset_b_in_a_localspace = matrix_a_transpose * (contact_context.offset_b);
let b_2_a_transform =
TransformWide::new(offset_b_in_a_localspace, &rotation_from_b_2_a_localspace);
let mut separating_axis_info = calculate_separating_axis(a, b, &b_2_a_transform);
let active_lanes =
u32x4::splat(contact_context.pair_count as u32).gt(u32x4::from([0, 1, 2, 3]));
let minimum_depth = -contact_context.speculative_margin;
let allow_contacts = active_lanes & (f32x4::ge(separating_axis_info.depth, minimum_depth));
if allow_contacts == bool32x4::FALSE {
manifold.reset(4);
} else {
let normal_dot_offset_b = separating_axis_info.normal.dot(offset_b_in_a_localspace);
let should_negate_normal = normal_dot_offset_b.gt(f32x4::ZERO);
separating_axis_info.normal = UnitVec3x4::lane_select(
should_negate_normal,
-separating_axis_info.normal,
separating_axis_info.normal,
);
manifold.normal =
(matrix_a * separating_axis_info.normal.as_vec3x4()).as_unit_vec3x4_unchecked();
let face_a = CuboidFace::new(
manifold.normal,
&matrix_a,
&a.half_length,
false,
&CuboidFaceInitConfig::default(),
);
let mut face_b = CuboidFace::new(
manifold.normal,
&matrix_b,
&b.half_length,
true,
&CuboidFaceInitConfig::default(),
);
face_b.center += contact_context.offset_b;
let mut candidates = Candidates::default();
let axis_id_ax = LOCAL_Z_ID.select(
face_a.use_x_as_face_normal,
LOCAL_X_ID.select(face_a.use_y_as_face_normal, LOCAL_Y_ID),
);
let axis_id_ay = LOCAL_Y_ID.select(
face_a.use_x_as_face_normal,
LOCAL_Z_ID.select(face_a.use_y_as_face_normal, LOCAL_X_ID),
);
let axis_id_az = LOCAL_X_ID.select(
face_a.use_x_as_face_normal,
LOCAL_Y_ID.select(face_a.use_y_as_face_normal, LOCAL_Z_ID),
);
let axis_id_bx = LOCAL_Z_ID.select(
face_b.use_x_as_face_normal,
LOCAL_X_ID.select(face_b.use_y_as_face_normal, LOCAL_Y_ID),
);
let axis_id_by = LOCAL_Y_ID.select(
face_b.use_x_as_face_normal,
LOCAL_Z_ID.select(face_b.use_y_as_face_normal, LOCAL_X_ID),
);
let axis_id_bz = LOCAL_X_ID.select(
face_b.use_x_as_face_normal,
LOCAL_Y_ID.select(face_b.use_y_as_face_normal, LOCAL_Z_ID),
);
let epsilon_scale = f32x4::min(face_a.max_half_span(), face_b.max_half_span());
let twice_axis_id_bx = axis_id_bx * u32x4::TWO;
let axis_z_edge_id_contribution = axis_id_bz * THREE_U32X4;
let edge_id_bx0 = twice_axis_id_bx + axis_id_by + axis_z_edge_id_contribution;
let edge_id_bx1 =
twice_axis_id_bx + axis_id_by * THREE_U32X4 + axis_z_edge_id_contribution;
let twice_axis_id_by = axis_id_by * u32x4::TWO;
let edge_id_by0 = axis_id_bx + twice_axis_id_by + axis_z_edge_id_contribution;
let edge_id_by1 =
axis_id_bx * THREE_U32X4 + twice_axis_id_by + axis_z_edge_id_contribution;
let vertices_of_a = face_a.vertices();
let face_pair_info = FacePairInfo {
a: &face_a,
b: &face_b,
contact_normal: &manifold.normal,
};
edges_of_face_b_clip_face_a(
&face_pair_info,
&vertices_of_a,
&EdgeClipContext::new(
contact_context.pair_count,
allow_contacts,
epsilon_scale,
edge_id_bx0,
edge_id_bx1,
edge_id_by0,
edge_id_by1,
),
&mut candidates,
);
let vertex_id00 = MAX_U32X4 - axis_id_az;
let vertex_id01 = MAX_U32X4 - (axis_id_az + axis_id_ay);
let vertex_id10 = MAX_U32X4 - (axis_id_az + axis_id_ax);
let vertex_id11 = MAX_U32X4 - (axis_id_az + axis_id_ax + axis_id_ay);
vertices_of_face_a_clip_face_b(
&vertices_of_a,
&face_pair_info,
&VertexClipContext::new(
contact_context.pair_count,
allow_contacts,
vertex_id00,
vertex_id01,
vertex_id10,
vertex_id11,
),
&mut candidates,
);
candidates.reduce_cuboid_pair(
&face_pair_info,
minimum_depth,
epsilon_scale,
contact_context.pair_count,
&mut manifold.contact_exists,
);
for (candidate, (offset_a, (depth, feature_id))) in candidates.value.iter().take(4).zip(
manifold.offset_a.iter_mut().zip(
manifold
.depth
.iter_mut()
.zip(manifold.feature_id.iter_mut()),
),
) {
transform_candidate_to_manifold(candidate, &face_b, offset_a, depth, feature_id);
}
for (offset_a, &depth) in manifold.offset_a.iter_mut().zip(manifold.depth.iter()) {
*offset_a -= manifold.normal * depth;
}
manifold.normal = manifold.normal.as_vec3x4().normalize_to_unit();
}
}
}
impl_pair_narrowphase!(Cuboid, Cuboid, CuboidWide, CuboidWide, 4);
#[cfg(test)]
mod tests {
use approx_det::assert_relative_eq;
use glam_det::nums::{f32x4, Num};
use glam_det::{Isometry3, UnitQuat, UnitQuatx4, UnitVec3, Vec3, Vec3x4};
use wasm_bindgen_test::wasm_bindgen_test;
use crate::collision_tasks::ShapeWideTester;
use crate::convex_contact_manifold::Convex4ContactManifoldWide;
use crate::shapes::CuboidWide;
use crate::traits::{CreateShapeWide, PairWideTest};
use crate::{Cuboid, PairTest, ShapeTester};
#[test]
#[wasm_bindgen_test]
fn test_contact_point_is_on_face() {
let _ = env_logger::builder().is_test(true).try_init();
let cuboid_a = Cuboid::new(Vec3::splat(1.0));
let cuboid_b = Cuboid::new(Vec3::splat(2.0));
let transform_a = Isometry3::IDENTITY;
let transform_b = Isometry3::from_rotation_translation(
UnitQuat::from_rotation_arc(
UnitVec3::NEG_Z,
UnitVec3::new_normalized(-1.0, -1.0, -1.0),
),
Vec3::new(0.0, 0.0, 1.9),
);
let a_wide = <CuboidWide as CreateShapeWide<1>>::create([&cuboid_a].into_iter());
let b_wide = <CuboidWide as CreateShapeWide<1>>::create([&cuboid_b].into_iter());
let speculative_margin = f32x4::splat(0.01);
let offset_b = Vec3x4::splat_soa(transform_b.translation - transform_a.translation);
let orientation_a = UnitQuatx4::splat_soa(transform_a.rotation);
let orientation_b = UnitQuatx4::splat_soa(transform_b.rotation);
let mut manifold = Convex4ContactManifoldWide::default();
let contact_context = crate::traits::ContactContext {
orientation_a: &orientation_a,
orientation_b: &orientation_b,
offset_b: &offset_b,
speculative_margin,
pair_count: 1,
complex_shape_container: None,
};
ShapeWideTester::test(&a_wide, &b_wide, &contact_context, &mut manifold);
assert_relative_eq!(manifold.normal.extract_lane(0), UnitVec3::NEG_Z);
assert_relative_eq!(manifold.offset_a[0].extract_lane(0).z, 0.5f32);
assert!(!manifold.contact_exists[1].extract(0));
assert!(!manifold.contact_exists[2].extract(0));
assert!(!manifold.contact_exists[3].extract(0));
}
#[test]
#[wasm_bindgen_test]
fn test_contact_point_is_on_face2() {
let _ = env_logger::builder().is_test(true).try_init();
let cuboid_a = Cuboid::new(Vec3::splat(1.0));
let cuboid_b = Cuboid::new(Vec3::splat(2.0));
let transform_a = Isometry3::IDENTITY;
let transform_b = Isometry3::from_translation(Vec3::new(0.0, 0.0, 1.4));
let a_wide = <CuboidWide as CreateShapeWide<1>>::create([&cuboid_a].into_iter());
let b_wide = <CuboidWide as CreateShapeWide<1>>::create([&cuboid_b].into_iter());
let speculative_margin = f32x4::splat(0.01);
let offset_b = Vec3x4::splat_soa(transform_b.translation - transform_a.translation);
let orientation_a = UnitQuatx4::splat_soa(transform_a.rotation);
let orientation_b = UnitQuatx4::splat_soa(transform_b.rotation);
let mut manifold = Convex4ContactManifoldWide::default();
let contact_context = crate::traits::ContactContext {
orientation_a: &orientation_a,
orientation_b: &orientation_b,
offset_b: &offset_b,
speculative_margin,
pair_count: 1,
complex_shape_container: None,
};
ShapeWideTester::test(&a_wide, &b_wide, &contact_context, &mut manifold);
assert!(manifold.contact_exists[0].extract(0));
assert!(manifold.contact_exists[1].extract(0));
assert!(manifold.contact_exists[2].extract(0));
assert!(manifold.contact_exists[3].extract(0));
assert_relative_eq!(manifold.normal.extract_lane(0), UnitVec3::NEG_Z);
assert_relative_eq!(manifold.offset_a[0].extract_lane(0).z, 0.5f32);
assert_relative_eq!(manifold.offset_a[1].extract_lane(0).z, 0.5f32);
assert_relative_eq!(manifold.offset_a[2].extract_lane(0).z, 0.5f32);
assert_relative_eq!(manifold.offset_a[3].extract_lane(0).z, 0.5f32);
let result = ShapeTester::test(
cuboid_a,
cuboid_b,
speculative_margin.extract(0),
offset_b.extract_lane(0),
orientation_a.extract_lane(0),
orientation_b.extract_lane(0),
None,
);
assert_eq!(result.count, 4);
}
}