use crate::BoundingVolume;
use bevy::{
prelude::*,
render::{mesh::VertexAttributeValues, pipeline::PrimitiveTopology},
};
use core::panic;
#[derive(Debug, Clone, Default)]
pub struct Aabb {
minimums: Vec3,
maximums: Vec3,
}
impl Aabb {
pub fn minimums(&self) -> Vec3 {
self.minimums
}
pub fn maximums(&self) -> Vec3 {
self.maximums
}
pub fn vertices(&self, transform: GlobalTransform) -> [Vec3; 8] {
let vertices_mesh_space = self.vertices_mesh_space();
[
transform.translation + vertices_mesh_space[0],
transform.translation + vertices_mesh_space[1],
transform.translation + vertices_mesh_space[2],
transform.translation + vertices_mesh_space[3],
transform.translation + vertices_mesh_space[4],
transform.translation + vertices_mesh_space[5],
transform.translation + vertices_mesh_space[6],
transform.translation + vertices_mesh_space[7],
]
}
pub fn vertices_mesh_space(&self) -> [Vec3; 8] {
[
Vec3::new(self.maximums.x, self.maximums.y, self.maximums.z),
Vec3::new(self.minimums.x, self.maximums.y, self.maximums.z),
Vec3::new(self.minimums.x, self.maximums.y, self.minimums.z),
Vec3::new(self.maximums.x, self.maximums.y, self.minimums.z),
Vec3::new(self.maximums.x, self.minimums.y, self.maximums.z),
Vec3::new(self.minimums.x, self.minimums.y, self.maximums.z),
Vec3::new(self.minimums.x, self.minimums.y, self.minimums.z),
Vec3::new(self.maximums.x, self.minimums.y, self.minimums.z),
]
}
pub fn from_extents(minimums: Vec3, maximums: Vec3) -> Self {
Aabb { minimums, maximums }
}
pub fn compute_aabb(vertices: &[Vec3]) -> Aabb {
let mut maximums = Vec3::new(f32::MIN, f32::MIN, f32::MIN);
let mut minimums = Vec3::new(f32::MAX, f32::MAX, f32::MAX);
for vertex in vertices.iter() {
maximums = vertex.max(maximums);
minimums = vertex.min(minimums);
}
Aabb { minimums, maximums }
}
}
impl BoundingVolume for Aabb {
fn new(mesh: &Mesh, transform: &GlobalTransform) -> Self {
let transform_matrix = Transform {
translation: Vec3::ZERO,
rotation: transform.rotation,
scale: transform.scale,
}
.compute_matrix();
if mesh.primitive_topology() != PrimitiveTopology::TriangleList {
panic!("Non-TriangleList mesh supplied for bounding box generation")
}
let vertices: Vec<Vec3> = match mesh.attribute(Mesh::ATTRIBUTE_POSITION) {
None => panic!("Mesh does not contain vertex positions"),
Some(vertex_values) => match &vertex_values {
VertexAttributeValues::Float3(positions) => positions
.iter()
.map(|coordinates| transform_matrix.transform_point3(Vec3::from(*coordinates)))
.collect(),
_ => panic!("Unexpected vertex types in ATTRIBUTE_POSITION"),
},
};
Self::compute_aabb(&vertices)
}
fn new_debug_mesh(&self, transform: &GlobalTransform) -> Mesh {
let mut mesh = Mesh::from(self);
let inverse_transform = Transform::from_matrix(
Mat4::from_scale_rotation_translation(transform.scale, transform.rotation, Vec3::ZERO)
.inverse(),
);
match mesh.attribute_mut(Mesh::ATTRIBUTE_POSITION) {
None => panic!("Mesh does not contain vertex positions"),
Some(vertex_values) => match vertex_values {
VertexAttributeValues::Float3(ref mut positions) => {
*positions = positions
.iter()
.map(|coordinates| {
inverse_transform.mul_vec3(Vec3::from(*coordinates)).into()
})
.collect()
}
_ => panic!("Unexpected vertex types in ATTRIBUTE_POSITION"),
},
};
mesh
}
fn update_on_transform_change(&self, mesh: &Mesh, transform: &GlobalTransform) -> Option<Self> {
Some(Self::new(mesh, transform))
}
fn outside_plane(
&self,
bound_vol_position: &GlobalTransform,
point: Vec3,
normal: Vec3,
) -> bool {
for vertex in self.vertices(*bound_vol_position).iter() {
if normal.dot(*vertex) + -normal.dot(point) < 0.0 {
return false;
}
}
true
}
}