use std::fmt::Debug;
use std::marker;
use std::ops::{Add, Mul, Sub};
use cgmath::{BaseFloat, EuclideanSpace, InnerSpace, Rotation, VectorSpace, Zero};
use core::{resolve_contact, ApplyAngular, ContactEvent, Inertia, Mass, PartialCrossProduct,
ResolveData, RigidBody, Velocity};
use core::{BodyPose, NextFrame};
use shrev::{EventChannel, ReaderId};
use specs::{Entity, Fetch, ReadStorage, System, WriteStorage};
pub struct ContactResolutionSystem<P, R, I, A, O>
where
P: EuclideanSpace,
P::Diff: Debug,
{
contact_reader: ReaderId<ContactEvent<Entity, P>>,
m: marker::PhantomData<(R, I, A, O)>,
}
impl<P, R, I, A, O> ContactResolutionSystem<P, R, I, A, O>
where
P: EuclideanSpace,
P::Scalar: BaseFloat,
P::Diff: VectorSpace + InnerSpace + Debug + PartialCrossProduct<P::Diff, Output = O>,
R: Rotation<P> + ApplyAngular<P::Scalar, A>,
O: PartialCrossProduct<P::Diff, Output = P::Diff>,
A: PartialCrossProduct<P::Diff, Output = P::Diff> + Clone + Zero,
for<'b> &'b A: Sub<O, Output = A> + Add<O, Output = A>,
I: Inertia<Orientation = R> + Mul<O, Output = O>,
{
pub fn new(contact_reader: ReaderId<ContactEvent<Entity, P>>) -> Self {
Self {
contact_reader,
m: marker::PhantomData,
}
}
}
impl<'a, P, R, I, A, O> System<'a> for ContactResolutionSystem<P, R, I, A, O>
where
P: EuclideanSpace + Send + Sync + 'static,
P::Scalar: BaseFloat + Send + Sync + 'static,
P::Diff: VectorSpace
+ InnerSpace
+ Debug
+ Send
+ Sync
+ 'static
+ PartialCrossProduct<P::Diff, Output = O>,
R: Rotation<P> + ApplyAngular<P::Scalar, A> + Send + Sync + 'static,
O: PartialCrossProduct<P::Diff, Output = P::Diff>,
A: PartialCrossProduct<P::Diff, Output = P::Diff> + Clone + Zero + Send + Sync + 'static,
for<'b> &'b A: Sub<O, Output = A> + Add<O, Output = A>,
I: Inertia<Orientation = R> + Mul<O, Output = O> + Send + Sync + 'static,
{
type SystemData = (
Fetch<'a, EventChannel<ContactEvent<Entity, P>>>,
ReadStorage<'a, Mass<P::Scalar, I>>,
ReadStorage<'a, RigidBody<P::Scalar>>,
WriteStorage<'a, NextFrame<Velocity<P::Diff, A>>>,
ReadStorage<'a, BodyPose<P, R>>,
WriteStorage<'a, NextFrame<BodyPose<P, R>>>,
);
fn run(&mut self, data: Self::SystemData) {
let (contacts, masses, bodies, mut next_velocities, poses, mut next_poses) = data;
for contact in contacts.read(&mut self.contact_reader) {
let change_set = resolve_contact(
&contact.contact,
ResolveData {
velocity: next_velocities.get(contact.bodies.0),
pose: next_poses
.get(contact.bodies.0)
.map(|p| &p.value)
.unwrap_or_else(|| poses.get(contact.bodies.0).unwrap()),
mass: masses.get(contact.bodies.0).unwrap(),
material: bodies.get(contact.bodies.0).map(|b| b.material()).unwrap(),
},
ResolveData {
velocity: next_velocities.get(contact.bodies.1),
pose: next_poses
.get(contact.bodies.1)
.map(|p| &p.value)
.unwrap_or_else(|| poses.get(contact.bodies.1).unwrap()),
mass: masses.get(contact.bodies.1).unwrap(),
material: bodies.get(contact.bodies.1).map(|b| b.material()).unwrap(),
},
);
change_set.0.apply(
next_poses.get_mut(contact.bodies.0),
next_velocities.get_mut(contact.bodies.0),
);
change_set.1.apply(
next_poses.get_mut(contact.bodies.1),
next_velocities.get_mut(contact.bodies.1),
);
}
}
}