pub mod aabb;
pub mod debug;
pub mod obb;
pub mod sphere;
use bevy::{prelude::*, transform::TransformSystem};
use debug::{update_debug_mesh_visibility, update_debug_meshes};
use std::fmt::Debug;
use std::marker::PhantomData;
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)]
pub enum BoundingSystem {
UpdateBounds,
UpdateDebug,
UpdateDebugVisibility,
}
#[derive(Default)]
pub struct BoundingVolumePlugin<T: BoundingVolume> {
marker: std::marker::PhantomData<T>,
}
impl<T> Plugin for BoundingVolumePlugin<T>
where
T: 'static + Send + Sync + BoundingVolume + Clone + Debug,
Mesh: From<&'static T>,
{
fn build(&self, app: &mut AppBuilder) {
app.add_system_to_stage(CoreStage::PreUpdate, spawn::<T>.system())
.add_system_to_stage(
CoreStage::PostUpdate,
update::<T>
.system()
.after(TransformSystem::TransformPropagate)
.label(BoundingSystem::UpdateBounds),
)
.add_system_to_stage(
CoreStage::PostUpdate,
update_debug_meshes::<T>
.system()
.after(BoundingSystem::UpdateBounds)
.label(BoundingSystem::UpdateDebug),
)
.add_system_to_stage(
CoreStage::PostUpdate,
update_debug_mesh_visibility::<T>
.system()
.after(BoundingSystem::UpdateDebug)
.before(bevy::render::RenderSystem::VisibleEntities),
);
}
}
#[derive(Debug, Clone)]
pub struct Bounded<T: BoundingVolume + Send + Sync>(PhantomData<T>);
impl<T: BoundingVolume + Send + Sync> Default for Bounded<T> {
fn default() -> Self {
Bounded(PhantomData::default())
}
}
pub trait BoundingVolume {
fn new(mesh: &Mesh, transform: &GlobalTransform) -> Self;
fn new_debug_mesh(&self, transform: &GlobalTransform) -> Mesh;
fn update_on_transform_change(
&self,
_mesh: &Mesh,
_transform: &GlobalTransform,
) -> Option<Self>
where
Self: Sized;
fn outside_plane(
&self,
bound_vol_position: &GlobalTransform,
point: Vec3,
normal: Vec3,
) -> bool;
}
#[allow(clippy::type_complexity)]
pub fn spawn<T: 'static + BoundingVolume + Send + Sync + Debug>(
mut commands: Commands,
meshes: Res<Assets<Mesh>>,
query: Query<(&Handle<Mesh>, &GlobalTransform, Entity), With<Bounded<T>>>,
) {
for (handle, transform, entity) in query.iter() {
if let Some(mesh) = meshes.get(handle) {
let new_bound = T::new(mesh, transform);
info!("New bounding volume generated: {:?}", new_bound);
commands
.entity(entity)
.insert(new_bound)
.remove::<Bounded<T>>();
}
}
}
fn update<T: 'static + BoundingVolume + Send + Sync>(
meshes: Res<Assets<Mesh>>,
changed_mesh_query: Query<Entity, Changed<Handle<Mesh>>>,
changed_transform_query: Query<Entity, Changed<GlobalTransform>>,
mut bound_vol_query: Query<(&mut T, &GlobalTransform, &Handle<Mesh>)>,
) {
for entity in changed_mesh_query.iter() {
if let Ok((mut bounding_vol, transform, handle)) = bound_vol_query.get_mut(entity) {
if let Some(mesh) = meshes.get(handle) {
*bounding_vol = T::new(mesh, transform);
}
}
}
for entity in changed_transform_query.iter() {
if changed_mesh_query.get(entity).is_err() {
if let Ok((mut bounding_vol, transform, handle)) = bound_vol_query.get_mut(entity) {
if let Some(mesh) = meshes.get(handle) {
if let Some(bound_vol) =
bounding_vol.update_on_transform_change(mesh, transform)
{
*bounding_vol = bound_vol;
}
}
}
}
}
}