use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::marker::PhantomData;
use cgmath::BaseFloat;
use cgmath::prelude::*;
use collision::dbvt::{DynamicBoundingVolumeTree, TreeValue};
use collision::prelude::*;
use specs::{Component, Entities, Entity, FetchMut, Join, ReadStorage, System, WriteStorage};
use core::{CollisionShape, NextFrame, Primitive};
#[derive(Debug)]
pub struct SpatialSortingSystem<P, T, D, B, Y = ()> {
entities: HashMap<Entity, usize>,
marker: PhantomData<(P, T, Y, B, D)>,
}
impl<P, T, D, B, Y> SpatialSortingSystem<P, T, D, B, Y> {
pub fn new() -> Self {
Self {
entities: HashMap::default(),
marker: PhantomData,
}
}
}
impl<'a, P, T, Y, D, B> System<'a> for SpatialSortingSystem<P, T, D, B, Y>
where
P: Primitive + ComputeBound<B> + Send + Sync + 'static,
B: Clone
+ Debug
+ Send
+ Sync
+ Union<B, Output = B>
+ Bound<Point = P::Point>
+ Contains<B>
+ SurfaceArea<Scalar = <P::Point as EuclideanSpace>::Scalar>
+ Send
+ Sync
+ 'static,
P::Point: Debug,
<P::Point as EuclideanSpace>::Scalar: BaseFloat + Send + Sync + 'static,
<P::Point as EuclideanSpace>::Diff: Debug + Send + Sync,
T: Component + Clone + Debug + Transform<P::Point> + Send + Sync,
Y: Default + Send + Sync + 'static,
for<'b: 'a> &'b T::Storage: Join<Type = &'b T>,
D: Send + Sync + 'static + TreeValue<Bound = B> + From<(Entity, B)>,
{
type SystemData = (
Entities<'a>,
ReadStorage<'a, T>,
ReadStorage<'a, NextFrame<T>>,
WriteStorage<'a, CollisionShape<P, T, B, Y>>,
FetchMut<'a, DynamicBoundingVolumeTree<D>>,
);
fn run(&mut self, (entities, poses, next_poses, mut shapes, mut tree): Self::SystemData) {
let mut keys = self.entities.keys().cloned().collect::<HashSet<Entity>>();
for (entity, pose, shape) in (&*entities, (&poses).open().1, &mut shapes).join() {
shape.update(&pose, None);
if let Some(node_index) = self.entities.get(&entity).cloned() {
tree.update_node(node_index, (entity, shape.bound().clone()).into());
}
}
for (entity, pose, next_pose, shape) in
(&*entities, &poses, (&next_poses).open().1, &mut shapes).join()
{
shape.update(&pose, Some(&next_pose.value));
if let Some(node_index) = self.entities.get(&entity).cloned() {
tree.update_node(node_index, (entity, shape.bound().clone()).into());
}
}
for (entity, _, shape) in (&*entities, &poses, &shapes).join() {
keys.remove(&entity);
if let None = self.entities.get(&entity) {
let node_index = tree.insert((entity, shape.bound().clone()).into());
self.entities.insert(entity, node_index);
}
}
for entity in keys {
match self.entities.get(&entity).cloned() {
Some(node_index) => {
tree.remove(node_index);
self.entities.remove(&entity);
}
None => (),
}
}
tree.update();
tree.do_refit();
}
}