use crate::ecs::mesh::components::InstancedMesh;
use crate::ecs::world::{Entity, World};
use crate::render::bounding_volume::{BoundingVolume, OrientedBoundingBox};
use crate::render::generational_registry::registry_entry_by_name;
use crate::render::mesh_cache::MeshCache;
use nalgebra_glm::vec3;
fn resolve_bounding_volume(mesh_cache: &MeshCache, mesh_name: &str) -> BoundingVolume {
if let Some(mesh) = registry_entry_by_name(&mesh_cache.registry, mesh_name)
&& let Some(bv) = &mesh.bounding_volume
{
return *bv;
}
BoundingVolume::from_mesh_type(mesh_name)
}
fn instanced_bounding_volume(mesh_cache: &MeshCache, instanced: &InstancedMesh) -> BoundingVolume {
let base = resolve_bounding_volume(mesh_cache, &instanced.mesh_name);
if instanced.instances.is_empty() {
return base;
}
let mut min = vec3(f32::MAX, f32::MAX, f32::MAX);
let mut max = vec3(f32::MIN, f32::MIN, f32::MIN);
for instance in &instanced.instances {
let obb = base.obb.transform(&instance.as_matrix());
for corner in obb.get_corners() {
min = min.inf(&corner);
max = max.sup(&corner);
}
}
BoundingVolume::new(
OrientedBoundingBox::from_aabb(min, max),
(max - min).norm() * 0.5,
)
}
pub fn ensure_bounding_volumes(world: &mut World) {
let mut pending: Vec<(Entity, BoundingVolume)> = Vec::new();
let mesh_cache = &world.resources.assets.mesh_cache;
for (entity, render_mesh) in world
.query_ref::<&crate::ecs::mesh::components::RenderMesh>()
.without::<BoundingVolume>()
.iter()
{
pending.push((
entity,
resolve_bounding_volume(mesh_cache, &render_mesh.name),
));
}
for (entity, instanced_mesh) in world
.query_ref::<&InstancedMesh>()
.without::<BoundingVolume>()
.iter()
{
pending.push((
entity,
instanced_bounding_volume(mesh_cache, instanced_mesh),
));
}
for (entity, bv) in pending {
world.set(entity, bv);
}
}