rhusics_ecs/physics/
setup.rs

1use std::fmt::Debug;
2use std::ops::{Add, Mul, Sub};
3
4use cgmath::{
5    BaseFloat, Basis2, EuclideanSpace, InnerSpace, Matrix3, Point2, Point3, Quaternion, Rotation,
6    Transform, Vector3, Zero,
7};
8use collision::dbvt::TreeValue;
9use collision::{Bound, ComputeBound, Contains, Discrete, HasBound, SurfaceArea, Union};
10use core::{
11    ApplyAngular, BroadPhase, GetId, Inertia, NarrowPhase, PartialCrossProduct, PhysicsTime, Pose,
12    Primitive,
13};
14use specs::prelude::{Component, DispatcherBuilder, Entity, Tracked};
15
16/// Create systems and add to a `Dispatcher` graph.
17///
18/// ### Parameters
19///
20/// - `dispatcher`: The dispatcher to add the systems to.
21/// - `broad_phase`: Broad phase to use
22/// - `narrow_phase`: Narrow phase to use
23/// - `spatial`: If spatial or basic collision detection should be used
24///
25/// ### Type parameters:
26///
27/// - `P`: Shape primitive
28/// - `T`: Pose (transform)
29/// - `B`: Bounding volume
30/// - `D`: Broad phase data, usually `TreeValueWrapped`.
31/// - `Y`: Collider
32/// - `V`: Broad phase algorithm
33/// - `N`: Narrow phase algorithm
34/// - `R`: Rotational quantity, `Basis2` or `Quaternion`
35/// - `A`: Angular velocity, `Scalar` or `Vector3`
36/// - `I`: Inertia, `Scalar` or `Matrix3`
37/// - `DT`: Time quantity, usually `DeltaTime`
38/// - `O`: Internal type used to abstract cross product for 2D vs 3D, `Scalar` or `Vector3`
39pub fn setup_dispatch<'a, 'b, P, T, B, D, Y, V, N, R, A, I, DT, O>(
40    dispatcher: &mut DispatcherBuilder<'a, 'b>,
41    broad_phase: V,
42    narrow_phase: N,
43    spatial: bool,
44) where
45    V: BroadPhase<D> + BroadPhase<(usize, D)> + 'static,
46    N: NarrowPhase<P, T, B, Y> + 'static,
47    P: Primitive + ComputeBound<B> + Send + Sync + 'static,
48    P::Point: Debug + Send + Sync + 'static,
49    <P::Point as EuclideanSpace>::Scalar: BaseFloat + Send + Sync + 'static,
50    <P::Point as EuclideanSpace>::Diff:
51        InnerSpace
52            + PartialCrossProduct<<P::Point as EuclideanSpace>::Diff, Output = O>
53            + Debug
54            + Send
55            + Sync
56            + 'static,
57    T: Debug + Component + Pose<P::Point, R> + Transform<P::Point> + Send + Sync + Clone + 'static,
58    T::Storage: Tracked,
59    Y: Default + Send + Sync + 'static,
60    B: Bound<Point = P::Point>
61        + Send
62        + Sync
63        + 'static
64        + Union<B, Output = B>
65        + Clone
66        + Contains<B>
67        + SurfaceArea<Scalar = <P::Point as EuclideanSpace>::Scalar>
68        + Discrete<B>
69        + Debug,
70    (usize, D): HasBound<Bound = B>,
71    D: TreeValue<Bound = B>
72        + HasBound<Bound = B>
73        + From<(Entity, B)>
74        + GetId<Entity>
75        + Send
76        + Sync
77        + 'static,
78    R: Rotation<P::Point>
79        + ApplyAngular<<P::Point as EuclideanSpace>::Scalar, A>
80        + Send
81        + Sync
82        + 'static,
83    I: Inertia<Orientation = R> + Mul<A, Output = A> + Mul<O, Output = O> + Send + Sync + 'static,
84    A: Mul<<P::Point as EuclideanSpace>::Scalar, Output = A>
85        + PartialCrossProduct<
86            <P::Point as EuclideanSpace>::Diff,
87            Output = <P::Point as EuclideanSpace>::Diff,
88        > + Zero
89        + Clone
90        + Copy
91        + Send
92        + Sync
93        + 'static,
94    DT: PhysicsTime<<P::Point as EuclideanSpace>::Scalar> + Default + Send + Sync + 'static,
95    O: PartialCrossProduct<
96            <P::Point as EuclideanSpace>::Diff,
97            Output = <P::Point as EuclideanSpace>::Diff,
98        > + Send
99        + Sync
100        + 'static,
101    for<'c> &'c A: Sub<O, Output = A> + Add<O, Output = A>,
102{
103    use {
104        BasicCollisionSystem, ContactResolutionSystem, CurrentFrameUpdateSystem,
105        NextFrameSetupSystem, SpatialCollisionSystem, SpatialSortingSystem,
106    };
107    dispatcher.add(
108        CurrentFrameUpdateSystem::<P::Point, R, A, T>::new(),
109        "physics_solver_system",
110        &[],
111    );
112    dispatcher.add(
113        NextFrameSetupSystem::<P::Point, R, I, A, T, DT>::new(),
114        "next_frame_setup",
115        &["physics_solver_system"],
116    );
117    if spatial {
118        dispatcher.add(
119            SpatialSortingSystem::<P, T, D, B, Y>::new(),
120            "spatial_sorting_system",
121            &["next_frame_setup"],
122        );
123        dispatcher.add(
124            SpatialCollisionSystem::<P, T, (usize, D), B, Y>::new()
125                .with_broad_phase(broad_phase)
126                .with_narrow_phase(narrow_phase),
127            "collision_system",
128            &["spatial_sorting_system"],
129        );
130    } else {
131        dispatcher.add(
132            BasicCollisionSystem::<P, T, D, B, Y>::new()
133                .with_broad_phase(broad_phase)
134                .with_narrow_phase(narrow_phase),
135            "collision_system",
136            &["next_frame_setup"],
137        );
138    }
139    dispatcher.add(
140        ContactResolutionSystem::<P::Point, R, I, A, O, T>::new(),
141        "contact_resolution",
142        &["collision_system"],
143    );
144}
145
146/// Create systems for 2D and add to a `Dispatcher` graph.
147///
148/// ### Parameters
149///
150/// - `dispatcher`: The dispatcher to add the systems to.
151/// - `broad_phase`: Broad phase to use
152/// - `narrow_phase`: Narrow phase to use
153/// - `spatial`: If spatial or basic collision detection should be used
154///
155/// ### Type parameters:
156///
157/// - `S`: Scalar type, `f32` or `f64`
158/// - `P`: Shape primitive
159/// - `T`: Pose (transform)
160/// - `B`: Bounding volume
161/// - `D`: Broad phase data, usually `TreeValueWrapped`.
162/// - `Y`: Collider
163/// - `V`: Broad phase algorithm
164/// - `N`: Narrow phase algorithm
165/// - `DT`: Time quantity, usually `DeltaTime`
166pub fn setup_dispatch_2d<'a, 'b, S, P, T, B, D, Y, V, N, DT>(
167    dispatcher: &mut DispatcherBuilder<'a, 'b>,
168    broad_phase: V,
169    narrow_phase: N,
170    spatial: bool,
171) where
172    V: BroadPhase<D> + BroadPhase<(usize, D)> + 'static,
173    N: NarrowPhase<P, T, B, Y> + 'static,
174    P: Primitive<Point = Point2<S>> + ComputeBound<B> + Send + Sync + 'static,
175    S: Inertia<Orientation = Basis2<S>> + BaseFloat + Send + Sync + 'static,
176    T: Component
177        + Pose<Point2<S>, Basis2<S>>
178        + Debug
179        + Transform<Point2<S>>
180        + Send
181        + Sync
182        + Clone
183        + 'static,
184    T::Storage: Tracked,
185    Y: Default + Send + Sync + 'static,
186    B: Bound<Point = Point2<S>>
187        + Send
188        + Sync
189        + 'static
190        + Union<B, Output = B>
191        + Clone
192        + Contains<B>
193        + SurfaceArea<Scalar = S>
194        + Discrete<B>
195        + Debug,
196    (usize, D): HasBound<Bound = B>,
197    D: TreeValue<Bound = B>
198        + HasBound<Bound = B>
199        + From<(Entity, B)>
200        + GetId<Entity>
201        + Send
202        + Sync
203        + 'static,
204    DT: PhysicsTime<S> + Default + Send + Sync + 'static,
205    for<'c> &'c S: Sub<S, Output = S> + Add<S, Output = S>,
206{
207    setup_dispatch::<P, T, B, D, Y, V, N, Basis2<S>, S, S, DT, S>(
208        dispatcher,
209        broad_phase,
210        narrow_phase,
211        spatial,
212    );
213}
214
215/// Create systems for 3sD and add to a `Dispatcher` graph.
216///
217/// ### Parameters
218///
219/// - `dispatcher`: The dispatcher to add the systems to.
220/// - `broad_phase`: Broad phase to use
221/// - `narrow_phase`: Narrow phase to use
222/// - `spatial`: If spatial or basic collision detection should be used
223///
224/// ### Type parameters:
225///
226/// - `S`: Scalar type, `f32` or `f64`
227/// - `P`: Shape primitive
228/// - `T`: Pose (transform)
229/// - `B`: Bounding volume
230/// - `D`: Broad phase data, usually `TreeValueWrapped`.
231/// - `Y`: Collider
232/// - `V`: Broad phase algorithm
233/// - `N`: Narrow phase algorithm
234/// - `DT`: Time quantity, usually `DeltaTime`
235pub fn setup_dispatch_3d<S, P, T, B, D, Y, V, N, DT>(
236    dispatcher: &mut DispatcherBuilder,
237    broad_phase: V,
238    narrow_phase: N,
239    spatial: bool,
240) where
241    V: BroadPhase<D> + BroadPhase<(usize, D)> + 'static,
242    N: NarrowPhase<P, T, B, Y> + 'static,
243    P: Primitive<Point = Point3<S>> + ComputeBound<B> + Send + Sync + 'static,
244    S: BaseFloat + Send + Sync + 'static,
245    T: Component
246        + Pose<Point3<S>, Quaternion<S>>
247        + Transform<Point3<S>>
248        + Debug
249        + Send
250        + Sync
251        + Clone
252        + 'static,
253    T::Storage: Tracked,
254    Y: Default + Send + Sync + 'static,
255    B: Bound<Point = Point3<S>>
256        + Send
257        + Sync
258        + 'static
259        + Union<B, Output = B>
260        + Clone
261        + Contains<B>
262        + SurfaceArea<Scalar = S>
263        + Discrete<B>
264        + Debug,
265    (usize, D): HasBound<Bound = B>,
266    D: TreeValue<Bound = B>
267        + HasBound<Bound = B>
268        + From<(Entity, B)>
269        + GetId<Entity>
270        + Send
271        + Sync
272        + 'static,
273    DT: PhysicsTime<S> + Default + Send + Sync + 'static,
274{
275    setup_dispatch::<P, T, B, D, Y, V, N, Quaternion<S>, Vector3<S>, Matrix3<S>, DT, Vector3<S>>(
276        dispatcher,
277        broad_phase,
278        narrow_phase,
279        spatial,
280    );
281}
282
283#[cfg(test)]
284mod tests {
285
286    use super::*;
287    use collide2d::{BodyPose2, SweepAndPrune2, GJK2};
288    use collide3d::{BodyPose3, SweepAndPrune3, GJK3};
289    use collision::dbvt::TreeValueWrapped;
290    use collision::primitive::{Primitive2, Primitive3};
291    use collision::{Aabb2, Aabb3};
292    use DeltaTime;
293
294    #[test]
295    fn test_dispatch() {
296        let mut builder = DispatcherBuilder::new();
297        setup_dispatch::<
298            Primitive2<f32>,
299            BodyPose2<f32>,
300            Aabb2<f32>,
301            TreeValueWrapped<Entity, Aabb2<f32>>,
302            (),
303            _,
304            _,
305            _,
306            _,
307            f32,
308            DeltaTime<f32>,
309            _,
310        >(&mut builder, SweepAndPrune2::new(), GJK2::new(), false);
311    }
312
313    #[test]
314    fn test_dispatch_2d() {
315        let mut builder = DispatcherBuilder::new();
316        setup_dispatch_2d::<
317            _,
318            Primitive2<f32>,
319            BodyPose2<f32>,
320            Aabb2<f32>,
321            TreeValueWrapped<Entity, Aabb2<f32>>,
322            (),
323            _,
324            _,
325            DeltaTime<f32>,
326        >(&mut builder, SweepAndPrune2::new(), GJK2::new(), false);
327    }
328
329    #[test]
330    fn test_dispatch_3d() {
331        let mut builder = DispatcherBuilder::new();
332        setup_dispatch_3d::<
333            _,
334            Primitive3<f32>,
335            BodyPose3<f32>,
336            Aabb3<f32>,
337            TreeValueWrapped<Entity, Aabb3<f32>>,
338            (),
339            _,
340            _,
341            DeltaTime<f32>,
342        >(&mut builder, SweepAndPrune3::new(), GJK3::new(), false);
343    }
344}