use std::collections::HashMap;
use rapier3d::geometry::{ColliderHandle, SolverFlags};
use rapier3d::math::Real;
use rapier3d::pipeline::{ContactModificationContext, PairFilterContext, PhysicsHooks};
#[derive(Copy, Clone, Debug, Default)]
pub struct PairOverride {
pub friction: Option<Real>,
pub margin: Option<Real>,
}
#[derive(Default, Clone, Debug)]
pub struct MjcfContactHooks {
pub(crate) exclude: std::collections::HashSet<(ColliderHandle, ColliderHandle)>,
pub(crate) overrides: HashMap<(ColliderHandle, ColliderHandle), PairOverride>,
}
impl MjcfContactHooks {
pub fn new() -> Self {
Self::default()
}
pub fn exclude(&mut self, a: ColliderHandle, b: ColliderHandle) {
self.exclude.insert((a, b));
self.exclude.insert((b, a));
}
pub fn add_override(&mut self, a: ColliderHandle, b: ColliderHandle, ov: PairOverride) {
self.overrides.insert((a, b), ov);
self.overrides.insert((b, a), ov);
}
pub fn has_excludes(&self) -> bool {
!self.exclude.is_empty()
}
pub fn has_overrides(&self) -> bool {
!self.overrides.is_empty()
}
}
impl PhysicsHooks for MjcfContactHooks {
fn filter_contact_pair(&self, ctx: &PairFilterContext) -> Option<SolverFlags> {
if self.exclude.contains(&(ctx.collider1, ctx.collider2)) {
None
} else {
Some(SolverFlags::COMPUTE_IMPULSES)
}
}
fn modify_solver_contacts(&self, ctx: &mut ContactModificationContext) {
let key = (ctx.collider1, ctx.collider2);
if let Some(ov) = self.overrides.get(&key) {
if let Some(f) = ov.friction {
for c in ctx.solver_contacts.iter_mut() {
c.friction = f;
}
}
if let Some(m) = ov.margin {
for c in ctx.solver_contacts.iter_mut() {
c.dist -= m;
}
}
}
}
}