1pub use collision::prelude::Primitive;
4pub use collision::{CollisionStrategy, ComputeBound, Contact};
5
6pub mod broad;
7pub mod narrow;
8
9use std::collections::HashSet;
10use std::fmt::Debug;
11use std::hash::Hash;
12
13use cgmath::prelude::*;
14use collision::dbvt::{DynamicBoundingVolumeTree, TreeValue, TreeValueWrapped};
15use collision::prelude::*;
16
17use self::broad::{broad_collide, BroadPhase};
18use self::narrow::{narrow_collide, NarrowPhase};
19
20pub trait Collider {
22 fn should_generate_contacts(&self, other: &Self) -> bool;
24}
25
26impl<'a> Collider for () {
27 fn should_generate_contacts(&self, _: &Self) -> bool {
28 true
29 }
30}
31
32#[derive(Debug, Clone, PartialOrd, PartialEq)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub enum CollisionMode {
36 Discrete,
38
39 Continuous,
41}
42
43#[derive(Debug, Clone)]
51pub struct ContactEvent<ID, P>
52where
53 P: EuclideanSpace,
54 P::Diff: Debug,
55{
56 pub bodies: (ID, ID),
58
59 pub contact: Contact<P>,
61}
62
63impl<ID, P> ContactEvent<ID, P>
64where
65 ID: Clone + Debug,
66 P: EuclideanSpace,
67 P::Diff: VectorSpace + Zero + Debug,
68{
69 pub fn new(bodies: (ID, ID), contact: Contact<P>) -> Self {
71 Self { bodies, contact }
72 }
73
74 pub fn new_simple(strategy: CollisionStrategy, bodies: (ID, ID)) -> Self {
76 Self::new(bodies, Contact::new(strategy))
77 }
78}
79
80#[derive(Debug, Clone)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101pub struct CollisionShape<P, T, B, Y = ()>
102where
103 P: Primitive,
104{
105 pub enabled: bool,
107 base_bound: B,
108 transformed_bound: B,
109 primitives: Vec<(P, T)>,
110 strategy: CollisionStrategy,
111 mode: CollisionMode,
112 ty: Y,
113}
114
115impl<P, T, B, Y> CollisionShape<P, T, B, Y>
116where
117 P: Primitive + ComputeBound<B>,
118 B: Bound<Point = P::Point> + Union<B, Output = B> + Clone,
119 T: Transform<P::Point>,
120 Y: Default,
121{
122 pub fn new_complex(
133 strategy: CollisionStrategy,
134 mode: CollisionMode,
135 primitives: Vec<(P, T)>,
136 ty: Y,
137 ) -> Self {
138 let bound: B = get_bound(&primitives);
139 Self {
140 base_bound: bound.clone(),
141 primitives,
142 enabled: true,
143 transformed_bound: bound,
144 strategy,
145 mode,
146 ty,
147 }
148 }
149
150 pub fn new_simple(strategy: CollisionStrategy, mode: CollisionMode, primitive: P) -> Self {
158 Self::new_complex(
159 strategy,
160 mode,
161 vec![(primitive, T::one())],
162 Default::default(),
163 )
164 }
165
166 pub fn new_simple_with_type(
174 strategy: CollisionStrategy,
175 mode: CollisionMode,
176 primitive: P,
177 ty: Y,
178 ) -> Self {
179 Self::new_complex(strategy, mode, vec![(primitive, T::one())], ty)
180 }
181
182 pub fn new_simple_offset(
191 strategy: CollisionStrategy,
192 mode: CollisionMode,
193 primitive: P,
194 transform: T,
195 ) -> Self {
196 Self::new_complex(
197 strategy,
198 mode,
199 vec![(primitive, transform)],
200 Default::default(),
201 )
202 }
203
204 pub fn update(&mut self, start: &T, end: Option<&T>) {
215 self.transformed_bound = match end {
216 None => self.base_bound.transform_volume(start),
217 Some(end_t) => {
218 let base = self.base_bound.transform_volume(end_t);
219 if self.mode == CollisionMode::Continuous {
220 base.union(&self.base_bound.transform_volume(start))
221 } else {
222 base
223 }
224 }
225 };
226 }
227
228 pub fn bound(&self) -> &B {
231 &self.transformed_bound
232 }
233
234 pub fn primitives(&self) -> &Vec<(P, T)> {
236 &self.primitives
237 }
238}
239
240impl<P, T, B, Y> HasBound for CollisionShape<P, T, B, Y>
241where
242 P: Primitive + ComputeBound<B>,
243 B: Bound<Point = P::Point> + Union<B, Output = B> + Clone,
244 T: Transform<P::Point>,
245 Y: Default,
246{
247 type Bound = B;
248
249 fn bound(&self) -> &Self::Bound {
250 &self.transformed_bound
251 }
252}
253
254fn get_bound<P, T, B>(primitives: &[(P, T)]) -> B
255where
256 P: Primitive + ComputeBound<B>,
257 B: Bound<Point = P::Point> + Union<B, Output = B>,
258 T: Transform<P::Point>,
259{
260 primitives
261 .iter()
262 .map(|&(ref p, ref t)| p.compute_bound().transform_volume(t))
263 .fold(B::empty(), |bound, b| bound.union(&b))
264}
265
266pub trait CollisionData<I, P, T, B, Y, D>
268where
269 P: Primitive,
270{
271 fn get_broad_data(&self) -> Vec<D>;
273 fn get_shape(&self, id: I) -> Option<&CollisionShape<P, T, B, Y>>;
275 fn get_pose(&self, id: I) -> Option<&T>;
277 fn get_dirty_poses(&self) -> Vec<I> {
279 Vec::default()
280 }
281 fn get_next_pose(&self, id: I) -> Option<&T>;
283}
284
285pub trait GetId<I> {
287 fn id(&self) -> I;
289}
290
291impl<I, B> GetId<I> for TreeValueWrapped<I, B>
292where
293 B: Bound,
294 I: Copy + Debug + Hash + Eq,
295 <B::Point as EuclideanSpace>::Diff: Debug,
296{
297 fn id(&self) -> I {
298 self.value
299 }
300}
301
302pub fn basic_collide<C, I, P, T, B, Y, D>(
314 data: &C,
315 broad: &mut Box<BroadPhase<D>>,
316 narrow: &Option<Box<NarrowPhase<P, T, B, Y>>>,
317) -> Vec<ContactEvent<I, P::Point>>
318where
319 C: CollisionData<I, P, T, B, Y, D>,
320 P: Primitive,
321 <P::Point as EuclideanSpace>::Diff: Debug,
322 I: Copy + Debug,
323 D: HasBound<Bound = B> + GetId<I>,
324 B: Bound<Point = P::Point>,
325{
326 let potentials = broad_collide(data, broad);
327 if potentials.is_empty() {
328 return Vec::default();
329 }
330 match *narrow {
331 Some(ref narrow) => narrow_collide(data, narrow, &potentials),
332 None => potentials
333 .iter()
334 .map(|&(left, right)| {
335 ContactEvent::new_simple(CollisionStrategy::CollisionOnly, (left, right))
336 }).collect::<Vec<_>>(),
337 }
338}
339
340pub fn tree_collide<C, I, P, T, B, Y, D>(
352 data: &C,
353 tree: &mut DynamicBoundingVolumeTree<D>,
354 broad: &mut Option<Box<BroadPhase<(usize, D)>>>,
355 narrow: &Option<Box<NarrowPhase<P, T, B, Y>>>,
356) -> Vec<ContactEvent<I, P::Point>>
357where
358 C: CollisionData<I, P, T, B, Y, D>,
359 P: Primitive,
360 <P::Point as EuclideanSpace>::Diff: Debug,
361 I: Copy + Debug + Hash + Eq,
362 D: HasBound<Bound = B> + GetId<I> + TreeValue<Bound = B>,
363 B: Bound<Point = P::Point>
364 + Clone
365 + SurfaceArea<Scalar = <P::Point as EuclideanSpace>::Scalar>
366 + Contains<B>
367 + Union<B, Output = B>
368 + Discrete<B>,
369{
370 use collision::algorithm::broad_phase::DbvtBroadPhase;
371 let potentials = match *broad {
372 Some(ref mut broad) => {
373 let p = broad.find_potentials(tree.values_mut());
374 tree.reindex_values();
375 p
376 }
377 None => {
378 let dirty_entities = data.get_dirty_poses().into_iter().collect::<HashSet<I>>();
379 let dirty = tree
380 .values()
381 .iter()
382 .map(|&(_, ref v)| dirty_entities.contains(&v.id()))
383 .collect::<Vec<_>>();
384 DbvtBroadPhase.find_collider_pairs(tree, &dirty[..])
385 }
386 };
387 let potentials = potentials
388 .iter()
389 .map(|&(ref l, ref r)| (tree.values()[*l].1.id(), tree.values()[*r].1.id()))
390 .collect::<Vec<_>>();
391 match *narrow {
392 Some(ref narrow) => narrow_collide(data, narrow, &potentials),
393 None => potentials
394 .iter()
395 .map(|&(left, right)| {
396 ContactEvent::new_simple(CollisionStrategy::CollisionOnly, (left, right))
397 }).collect::<Vec<_>>(),
398 }
399}