use std::sync::Arc;
use slotmap::{SecondaryMap, SlotMap};
use crate::RenderContext;
use crate::mesh::{CpuMesh, GpuMesh, MeshError};
use crate::renderer::GpuMeshInstance;
slotmap::new_key_type! {
pub struct CpuModelMeshKey;
}
pub struct CpuMeshInstance {
pub mesh: CpuModelMeshKey,
pub world_from_mesh: glam::Affine3A,
}
#[derive(Default)]
pub struct CpuModel {
pub meshes: SlotMap<CpuModelMeshKey, CpuMesh>,
pub instances: Vec<CpuMeshInstance>,
pub bbox: macaw::BoundingBox,
}
impl CpuModel {
pub fn from_single_mesh(mesh: CpuMesh) -> Self {
let mut model = Self::default();
model.add_single_instance_mesh(mesh);
model
}
pub fn add_single_instance_mesh(&mut self, mesh: CpuMesh) {
self.bbox = self.bbox.union(mesh.bbox);
let mesh_key = self.meshes.insert(mesh);
self.instances.push(CpuMeshInstance {
mesh: mesh_key,
world_from_mesh: glam::Affine3A::IDENTITY,
});
}
pub fn into_gpu_meshes(self, ctx: &RenderContext) -> Result<Vec<GpuMeshInstance>, MeshError> {
let mut gpu_meshes = SecondaryMap::with_capacity(self.meshes.len());
for (mesh_key, mesh) in &self.meshes {
gpu_meshes.insert(mesh_key, Arc::new(GpuMesh::new(ctx, mesh)?));
}
Ok(self
.instances
.into_iter()
.filter_map(|instance| {
Some(GpuMeshInstance {
gpu_mesh: gpu_meshes.get(instance.mesh)?.clone(),
world_from_mesh: instance.world_from_mesh,
additive_tint: Default::default(),
outline_mask_ids: Default::default(),
picking_layer_id: Default::default(),
})
})
.collect())
}
}