use super::Shape;
use crate::aabb::farthest_point_on_aabb;
use crate::broad_phase::{proxy_type, BroadPhase};
use crate::compound::compute_compound_aabb;
use crate::constants::speculative_distance;
use crate::core::NULL_INDEX;
use crate::geometry::{
compute_capsule_aabb, compute_capsule_mass, compute_sphere_aabb, compute_sphere_mass, MassData,
ShapeExtent,
};
use crate::height_field::compute_height_field_aabb;
use crate::hull::{compute_hull_aabb, compute_hull_extent, compute_hull_mass};
use crate::math_functions::{
aabb_center, abs, add, lerp, max, min_float, sub, Aabb, Transform, Vec3, WorldTransform,
TRANSFORM_IDENTITY, VEC3_ZERO,
};
use crate::mesh::compute_mesh_aabb;
use crate::types::BodyType;
use super::ShapeGeometry;
pub(crate) fn update_shape_aabbs(
shape: &mut Shape,
transform: WorldTransform,
proxy_type_: BodyType,
) {
let speculative = speculative_distance();
let aabb_margin = shape.aabb_margin;
let aabb = compute_fat_shape_aabb(shape, transform, speculative);
shape.aabb = aabb;
let margin = if proxy_type_ == BodyType::Static {
speculative
} else {
aabb_margin
};
shape.fat_aabb = Aabb {
lower_bound: Vec3 {
x: aabb.lower_bound.x - margin,
y: aabb.lower_bound.y - margin,
z: aabb.lower_bound.z - margin,
},
upper_bound: Vec3 {
x: aabb.upper_bound.x + margin,
y: aabb.upper_bound.y + margin,
z: aabb.upper_bound.z + margin,
},
};
}
pub fn create_shape_proxy(
shape: &mut Shape,
bp: &mut BroadPhase,
type_: BodyType,
transform: WorldTransform,
force_pair_creation: bool,
) {
debug_assert!(shape.proxy_key == NULL_INDEX);
update_shape_aabbs(shape, transform, type_);
shape.proxy_key = bp.create_proxy(
type_,
shape.fat_aabb,
shape.filter.category_bits,
shape.id,
force_pair_creation,
);
debug_assert!((proxy_type(shape.proxy_key) as usize) < crate::types::BODY_TYPE_COUNT);
}
pub fn destroy_shape_proxy(shape: &mut Shape, bp: &mut BroadPhase) {
if shape.proxy_key != NULL_INDEX {
bp.destroy_proxy(shape.proxy_key);
shape.proxy_key = NULL_INDEX;
}
}
pub fn compute_shape_aabb(shape: &Shape, transform: Transform) -> Aabb {
match &shape.geometry {
ShapeGeometry::Capsule(capsule) => compute_capsule_aabb(capsule, transform),
ShapeGeometry::Compound(compound) => compute_compound_aabb(compound, transform),
ShapeGeometry::HeightField(hf) => compute_height_field_aabb(hf, transform),
ShapeGeometry::Hull(hull) => compute_hull_aabb(hull, transform),
ShapeGeometry::Mesh { data, scale } => compute_mesh_aabb(data, transform, *scale),
ShapeGeometry::Sphere(sphere) => compute_sphere_aabb(sphere, transform),
}
}
pub fn compute_fat_shape_aabb(shape: &Shape, transform: WorldTransform, extra: f32) -> Aabb {
let r = Vec3 {
x: extra,
y: extra,
z: extra,
};
#[cfg(feature = "double-precision")]
{
use crate::math_functions::{offset_aabb, VEC3_ZERO};
let rotation = Transform {
p: VEC3_ZERO,
q: transform.q,
};
let mut local_box = compute_shape_aabb(shape, rotation);
local_box.lower_bound = sub(local_box.lower_bound, r);
local_box.upper_bound = add(local_box.upper_bound, r);
offset_aabb(local_box, transform.p)
}
#[cfg(not(feature = "double-precision"))]
{
let mut aabb = compute_shape_aabb(shape, transform);
aabb.lower_bound = sub(aabb.lower_bound, r);
aabb.upper_bound = add(aabb.upper_bound, r);
aabb
}
}
pub fn get_shape_centroid(shape: &Shape) -> Vec3 {
match &shape.geometry {
ShapeGeometry::Capsule(capsule) => lerp(capsule.center1, capsule.center2, 0.5),
ShapeGeometry::Compound(compound) => {
let aabb = compute_compound_aabb(compound, TRANSFORM_IDENTITY);
aabb_center(aabb)
}
ShapeGeometry::Sphere(sphere) => sphere.center,
ShapeGeometry::Hull(hull) => hull.center,
ShapeGeometry::Mesh { data, scale } => {
let aabb = compute_mesh_aabb(data, TRANSFORM_IDENTITY, *scale);
aabb_center(aabb)
}
ShapeGeometry::HeightField(hf) => {
let aabb = compute_height_field_aabb(hf, TRANSFORM_IDENTITY);
aabb_center(aabb)
}
}
}
pub fn compute_shape_mass(shape: &Shape) -> MassData {
match &shape.geometry {
ShapeGeometry::Capsule(capsule) => compute_capsule_mass(capsule, shape.density),
ShapeGeometry::Hull(hull) => compute_hull_mass(hull, shape.density),
ShapeGeometry::Sphere(sphere) => compute_sphere_mass(sphere, shape.density),
_ => MassData::default(),
}
}
pub fn make_shape_proxy(shape: &Shape) -> crate::distance::ShapeProxy {
use crate::distance::make_proxy;
use crate::hull::get_hull_points;
match &shape.geometry {
ShapeGeometry::Capsule(capsule) => {
make_proxy(&[capsule.center1, capsule.center2], capsule.radius)
}
ShapeGeometry::Sphere(sphere) => make_proxy(&[sphere.center], sphere.radius),
ShapeGeometry::Hull(hull) => make_proxy(get_hull_points(hull), 0.0),
_ => {
debug_assert!(false, "make_shape_proxy is for convex shapes only");
make_proxy(&[VEC3_ZERO], 0.0)
}
}
}
pub fn compute_shape_extent(shape: &Shape, local_center: Vec3) -> ShapeExtent {
let mut extent = ShapeExtent::default();
match &shape.geometry {
ShapeGeometry::Capsule(capsule) => {
let radius = capsule.radius;
extent.min_extent = radius;
let c1 = sub(capsule.center1, local_center);
let c2 = sub(capsule.center2, local_center);
let r = Vec3 {
x: radius,
y: radius,
z: radius,
};
extent.max_extent = add(max(c1, c2), r);
}
ShapeGeometry::Compound(compound) => {
let aabb = compute_compound_aabb(compound, TRANSFORM_IDENTITY);
let r1 = crate::math_functions::length(sub(aabb.lower_bound, local_center));
let r2 = crate::math_functions::length(sub(aabb.upper_bound, local_center));
extent.min_extent = min_float(r1, r2);
let p = farthest_point_on_aabb(aabb, local_center);
extent.max_extent = abs(sub(p, local_center));
}
ShapeGeometry::Sphere(sphere) => {
let radius = sphere.radius;
extent.min_extent = radius;
let r = Vec3 {
x: radius,
y: radius,
z: radius,
};
let p = add(sub(sphere.center, local_center), r);
extent.max_extent = abs(sub(p, local_center));
}
ShapeGeometry::Hull(hull) => {
extent = compute_hull_extent(hull, local_center);
}
ShapeGeometry::Mesh { data, scale } => {
let aabb = compute_mesh_aabb(data, TRANSFORM_IDENTITY, *scale);
let r1 = crate::math_functions::length(sub(aabb.lower_bound, local_center));
let r2 = crate::math_functions::length(sub(aabb.upper_bound, local_center));
extent.min_extent = min_float(r1, r2);
let p = farthest_point_on_aabb(aabb, local_center);
extent.max_extent = abs(p);
}
ShapeGeometry::HeightField(_) => {}
}
extent
}