use super::gjk::shape_distance;
use super::types::{DistanceInput, ShapeCastPairInput, SimplexCache};
use crate::collision::CastOutput;
use crate::constants::linear_slop;
use crate::math_functions::{dot, is_normalized, lerp, max_float, mul_add};
pub fn shape_cast(input: &ShapeCastPairInput) -> CastOutput {
let slop = linear_slop();
let total_radius = input.proxy_a.radius + input.proxy_b.radius;
let mut target = max_float(slop, total_radius - slop);
let tolerance = 0.25 * slop;
debug_assert!(target > tolerance);
let mut cache = SimplexCache::default();
let mut fraction = 0.0;
let mut distance_input = DistanceInput {
proxy_a: input.proxy_a,
proxy_b: input.proxy_b,
transform: input.transform,
use_radii: false,
};
let delta2 = input.translation_b;
let mut output = CastOutput::default();
let max_iterations = 20;
for iteration in 0..max_iterations {
output.iterations += 1;
let distance_output = shape_distance(&distance_input, &mut cache, None);
if distance_output.distance < target + tolerance {
if iteration == 0 {
if input.can_encroach && distance_output.distance > 2.0 * slop {
target = distance_output.distance - slop;
} else {
output.hit = true;
let c1 = mul_add(
distance_output.point_a,
input.proxy_a.radius,
distance_output.normal,
);
let c2 = mul_add(
distance_output.point_b,
-input.proxy_b.radius,
distance_output.normal,
);
output.point = lerp(c1, c2, 0.5);
return output;
}
} else {
debug_assert!(
distance_output.distance > 0.0 && is_normalized(distance_output.normal)
);
output.fraction = fraction;
output.point = mul_add(
distance_output.point_a,
input.proxy_a.radius,
distance_output.normal,
);
output.normal = distance_output.normal;
output.hit = true;
return output;
}
}
debug_assert!(distance_output.distance > 0.0);
debug_assert!(is_normalized(distance_output.normal));
let denominator = dot(delta2, distance_output.normal);
if denominator >= 0.0 {
return output;
}
fraction += (target - distance_output.distance) / denominator;
if fraction >= input.max_fraction {
return output;
}
distance_input.transform.p = mul_add(input.transform.p, fraction, delta2);
}
output
}