use rapier::prelude::{Aabb, VoxelData, VoxelState, Voxels};
use crate::math::{IVect, Vect};
#[cfg(feature = "dim2")]
use bevy::math::bounding::Aabb2d as BevyAabb;
#[cfg(feature = "dim3")]
use bevy::math::bounding::Aabb3d as BevyAabb;
#[cfg(feature = "dim2")]
fn aabb_na_from_bevy(aabb: &BevyAabb) -> Aabb {
rapier::parry::bounding_volume::Aabb::new(aabb.min, aabb.max)
}
#[cfg(feature = "dim3")]
fn aabb_na_from_bevy(aabb: &BevyAabb) -> Aabb {
rapier::parry::bounding_volume::Aabb::new(aabb.min.into(), aabb.max.into())
}
#[cfg(feature = "dim2")]
fn aabb_bevy_from_na(aabb: &Aabb) -> BevyAabb {
BevyAabb {
min: aabb.mins,
max: aabb.maxs,
}
}
#[cfg(feature = "dim3")]
fn aabb_bevy_from_na(aabb: &Aabb) -> BevyAabb {
BevyAabb {
min: aabb.mins.into(),
max: aabb.maxs.into(),
}
}
#[derive(Copy, Clone)]
pub struct VoxelsView<'a> {
pub raw: &'a Voxels,
}
macro_rules! impl_ref_methods(
($View: ident) => {
impl<'a> $View<'a> {
pub fn total_memory_size(&self) -> usize {
self.raw.total_memory_size()
}
pub fn heap_memory_size(&self) -> usize {
self.raw.heap_memory_size()
}
pub fn extents(&self) -> Vect {
self.raw.local_aabb().extents()
}
pub fn domain_center(&self) -> Vect {
self.raw.local_aabb().center()
}
pub fn is_voxel_in_bounds(&self, key: IVect) -> bool {
let [mins, maxs] = self.raw.domain();
#[cfg(feature = "dim2")]
{
key.x >= mins.x && key.y >= mins.y && key.x < maxs.x && key.y < maxs.y
}
#[cfg(feature = "dim3")]
{
key.x >= mins.x
&& key.y >= mins.y
&& key.z >= mins.z
&& key.x < maxs.x
&& key.y < maxs.y
&& key.z < maxs.z
}
}
pub fn voxel_aabb(&self, key: IVect) -> BevyAabb {
aabb_bevy_from_na(&self.raw.voxel_aabb(key.into()))
}
pub fn voxel_state(&self, key: IVect) -> Option<VoxelState> {
self.raw.voxel_state(key.into())
}
pub fn voxel_at_point_unchecked(&self, point: Vect) -> IVect {
self.raw.voxel_at_point(point)
}
pub fn voxel_at_point(&self, pt: Vect) -> Option<IVect> {
let voxel = self.voxel_at_point_unchecked(pt);
if self.is_voxel_in_bounds(voxel) {
Some(voxel)
} else {
None
}
}
pub fn clamp_voxel(&self, key: IVect) -> IVect {
let [mins, maxs] = self.raw.domain();
#[cfg(feature = "dim2")]
{
IVect::new(
key.x.clamp(mins.x, maxs.x - 1),
key.y.clamp(mins.y, maxs.y - 1),
)
}
#[cfg(feature = "dim3")]
{
IVect::new(
key.x.clamp(mins.x, maxs.x - 1),
key.y.clamp(mins.y, maxs.y - 1),
key.z.clamp(mins.z, maxs.z - 1),
)
}
}
pub fn voxel_range_intersecting_local_aabb(&self, aabb: &BevyAabb) -> [IVect; 2] {
let res = self
.raw
.voxel_range_intersecting_local_aabb(&aabb_na_from_bevy(aabb));
[res[0].into(), res[1].into()]
}
pub fn voxel_range_aabb(&self, mins: IVect, maxs: IVect) -> BevyAabb {
aabb_bevy_from_na(&self.raw.voxel_range_aabb(mins.into(), maxs.into()))
}
pub fn align_aabb_to_grid(&self, aabb: &BevyAabb) -> BevyAabb {
aabb_bevy_from_na(&self.raw.align_aabb_to_grid(&aabb_na_from_bevy(aabb)))
}
pub fn voxels_intersecting_local_aabb(
&self,
aabb: &BevyAabb,
) -> impl Iterator<Item = VoxelData> + '_ {
self.raw
.voxels_intersecting_local_aabb(&aabb_na_from_bevy(aabb))
}
pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
self.raw.voxels()
}
#[cfg(feature = "dim2")]
pub fn split_with_box(&self, aabb: &BevyAabb) -> (Option<Voxels>, Option<Voxels>) {
self.raw.split_with_box(&aabb_na_from_bevy(aabb))
}
pub fn voxels_in_range(
&self,
mins: IVect,
maxs: IVect,
) -> impl Iterator<Item = VoxelData> + '_ {
self.raw.voxels_in_range(mins.into(), maxs.into())
}
}
}
);
impl_ref_methods!(VoxelsView);
pub struct VoxelsViewMut<'a> {
pub raw: &'a mut Voxels,
}
impl_ref_methods!(VoxelsViewMut);
impl<'a> VoxelsViewMut<'a> {
pub fn try_set_voxel(&mut self, key: IVect, is_filled: bool) -> Option<VoxelState> {
if self.is_voxel_in_bounds(key) {
Some(self.raw.set_voxel(key, is_filled))
} else {
None
}
}
pub fn set_voxel(&mut self, key: IVect, is_filled: bool) -> VoxelState {
self.raw.set_voxel(key, is_filled)
}
pub fn crop(&mut self, domain_mins: IVect, domain_maxs: IVect) {
self.raw.crop(domain_mins, domain_maxs);
}
}