use crate::ecs::bounding_volume::components::{BoundingVolume, OrientedBoundingBox};
use crate::ecs::generational_registry::registry_entry_by_name;
use crate::ecs::mesh::components::InstancedMesh;
use crate::ecs::prefab::resources::MeshCache;
use crate::ecs::world::{BOUNDING_VOLUME, Entity, INSTANCED_MESH, RENDER_MESH, World};
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;
world
.core
.query()
.with(RENDER_MESH)
.without(BOUNDING_VOLUME)
.iter(|entity, table, idx| {
let mesh_name = &table.render_mesh[idx].name;
pending.push((entity, resolve_bounding_volume(mesh_cache, mesh_name)));
});
world
.core
.query()
.with(INSTANCED_MESH)
.without(BOUNDING_VOLUME)
.iter(|entity, table, idx| {
pending.push((
entity,
instanced_bounding_volume(mesh_cache, &table.instanced_mesh[idx]),
));
});
for (entity, bv) in pending {
world.core.add_components(entity, BOUNDING_VOLUME);
world.core.set_bounding_volume(entity, bv);
}
}