use crate::{Float, Frustum, Vec3, Vec4};
use core::fmt::Debug;
pub trait BVol<T: Float + Debug> {
fn get_aabb(&self) -> AABB<T>;
fn test_against_plane(&self, plane: &Vec4<T>) -> bool;
fn test_against_frustum(&self, frustum: &Frustum<T>, mut mask: u8) -> u8 {
for i in 0..6 {
if self.test_against_plane(&frustum.planes[i as usize]) {
return u8::max_value();
} else {
mask |= 0b1000_0000u8 >> i;
}
}
if !frustum.test_against_aabb(&self.get_aabb()) {
return u8::max_value();
}
mask
}
fn coherent_test_against_frustum(&self, frustum: &Frustum<T>, lpindex: u8) -> (bool, u8) {
if self.test_against_plane(&frustum.planes[lpindex as usize]) {
return (false, lpindex);
}
for i in 0..6 {
if (i != lpindex) && self.test_against_plane(&frustum.planes[i as usize]) {
return (false, i);
}
}
if !frustum.test_against_aabb(&self.get_aabb()) {
return (false, lpindex);
}
(true, lpindex)
}
}
pub struct BoundingSphere<T: Float + Debug> {
pub center: Vec3<T>,
pub radius: T,
}
impl<T: Float + Debug> BoundingSphere<T> {
pub fn new(center: impl Into<Vec3<T>>, radius: T) -> BoundingSphere<T> {
BoundingSphere {
center: center.into(),
radius,
}
}
}
impl<T: Float + Debug> BVol<T> for BoundingSphere<T> {
fn get_aabb(&self) -> AABB<T> {
AABB {
min: Vec3::new(
self.center[0] - self.radius,
self.center[1] - self.radius,
self.center[2] - self.radius,
),
max: Vec3::new(
self.center[0] + self.radius,
self.center[1] + self.radius,
self.center[2] + self.radius,
),
}
}
fn test_against_plane(&self, plane: &Vec4<T>) -> bool {
dist_bpp(plane, self.center) < -self.radius
}
}
pub struct AABB<T: Float + Debug> {
pub min: Vec3<T>,
pub max: Vec3<T>,
}
impl<T: Float + Debug> AABB<T> {
pub fn new<P>(min: P, max: P) -> AABB<T>
where
P: Into<Vec3<T>>,
{
AABB {
min: min.into(),
max: max.into(),
}
}
}
impl<T: Float + Debug> BVol<T> for AABB<T> {
fn get_aabb(&self) -> AABB<T> {
AABB {
min: self.min,
max: self.max,
}
}
fn test_against_plane(&self, plane: &Vec4<T>) -> bool {
dist_bpp(plane, mi_vertex(plane, self)) < T::zero()
}
}
impl<T: Float + Debug> From<[(T, T, T); 2]> for AABB<T> {
fn from(v: [(T, T, T); 2]) -> Self {
Self::new([v[0].0, v[0].1, v[0].2], [v[1].0, v[1].1, v[1].2])
}
}
pub fn dist_bpp<T: Float>(plane: &Vec4<T>, point: Vec3<T>) -> T {
plane.x * point.x + plane.y * point.y + plane.z * point.z + plane.w
}
pub fn mi_vertex<T: Float + Debug>(plane: &Vec4<T>, aabb: &AABB<T>) -> Vec3<T> {
Vec3::new(
if plane.x >= T::zero() {
aabb.max.x
} else {
aabb.min.x
},
if plane.y >= T::zero() {
aabb.max.y
} else {
aabb.min.y
},
if plane.z >= T::zero() {
aabb.max.z
} else {
aabb.min.z
},
)
}
pub fn mo_vertex<T: Float + Debug>(plane: &Vec4<T>, aabb: &AABB<T>) -> Vec3<T> {
Vec3::new(
if plane.x >= T::zero() {
aabb.min.x
} else {
aabb.max.x
},
if plane.y >= T::zero() {
aabb.min.y
} else {
aabb.max.y
},
if plane.z >= T::zero() {
aabb.min.z
} else {
aabb.max.z
},
)
}