use std::collections::HashMap;
use crate::engine::graphics::MeshUploader;
use crate::engine::graphics::mesh::CpuMesh;
use crate::engine::graphics::mesh::MeshFactory;
use crate::engine::graphics::primitives::{CpuMeshHandle, MeshHandle};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinMeshType {
Triangle2D,
Quad2D,
Cube,
Tetrahedron,
Sphere,
Cone,
Circle2D,
}
#[derive(Debug, Default)]
pub struct RenderAssets {
cpu_meshes: Vec<CpuMesh>,
gpu_meshes: HashMap<CpuMeshHandle, MeshHandle>,
imported_meshes: HashMap<String, CpuMeshHandle>,
builtin_meshes: HashMap<BuiltinMeshType, CpuMeshHandle>,
wireframe_box_meshes: HashMap<u32, CpuMeshHandle>,
wireframe_square_meshes: HashMap<u32, CpuMeshHandle>,
wireframe_sphere_meshes: HashMap<(u32, u32, u32), CpuMeshHandle>,
wireframe_icosahedron_meshes: HashMap<(u32, u32, u32), CpuMeshHandle>,
capsule_y_meshes: HashMap<(u32, u32), CpuMeshHandle>,
}
impl RenderAssets {
pub fn new() -> Self {
let mut s = Self::default();
s.register_builtin_meshes();
s
}
pub fn get_mesh(&mut self, mesh: BuiltinMeshType) -> CpuMeshHandle {
self.ensure_builtin_mesh(mesh)
}
fn register_builtin_meshes(&mut self) {
let _ = self.ensure_builtin_mesh(BuiltinMeshType::Triangle2D);
let _ = self.ensure_builtin_mesh(BuiltinMeshType::Quad2D);
let _ = self.ensure_builtin_mesh(BuiltinMeshType::Cube);
let _ = self.ensure_builtin_mesh(BuiltinMeshType::Tetrahedron);
let _ = self.ensure_builtin_mesh(BuiltinMeshType::Sphere);
let _ = self.ensure_builtin_mesh(BuiltinMeshType::Cone);
let _ = self.ensure_builtin_mesh(BuiltinMeshType::Circle2D);
}
fn ensure_builtin_mesh(&mut self, mesh: BuiltinMeshType) -> CpuMeshHandle {
if let Some(h) = self.builtin_meshes.get(&mesh).copied() {
return h;
}
let cpu_mesh = match mesh {
BuiltinMeshType::Triangle2D => MeshFactory::triangle_2d(),
BuiltinMeshType::Quad2D => MeshFactory::quad_2d(),
BuiltinMeshType::Cube => MeshFactory::cube(),
BuiltinMeshType::Tetrahedron => MeshFactory::tetrahedron(),
BuiltinMeshType::Sphere => MeshFactory::sphere(),
BuiltinMeshType::Cone => MeshFactory::cone(32),
BuiltinMeshType::Circle2D => MeshFactory::circle_2d(0.45, 0.5, 64),
};
let h = self.register_mesh(cpu_mesh);
self.builtin_meshes.insert(mesh, h);
h
}
pub fn register_mesh(&mut self, mesh: CpuMesh) -> CpuMeshHandle {
let h = CpuMeshHandle(self.cpu_meshes.len() as u32);
self.cpu_meshes.push(mesh);
h
}
pub fn wireframe_box_mesh(&mut self, thickness: f32) -> CpuMeshHandle {
let thickness = thickness.clamp(1.0e-4, 1.0);
let key = thickness.to_bits();
if let Some(handle) = self.wireframe_box_meshes.get(&key).copied() {
return handle;
}
let handle = self.register_mesh(MeshFactory::wireframe_box(thickness));
self.wireframe_box_meshes.insert(key, handle);
handle
}
pub fn wireframe_square_mesh(&mut self, thickness: f32) -> CpuMeshHandle {
let thickness = thickness.clamp(1.0e-4, 0.5);
let key = thickness.to_bits();
if let Some(handle) = self.wireframe_square_meshes.get(&key).copied() {
return handle;
}
let handle = self.register_mesh(MeshFactory::wireframe_square(thickness));
self.wireframe_square_meshes.insert(key, handle);
handle
}
pub fn wireframe_sphere_mesh(
&mut self,
latitude_segments: u32,
longitude_segments: u32,
thickness: f32,
) -> CpuMeshHandle {
let latitude_segments = latitude_segments.max(2);
let longitude_segments = longitude_segments.max(3);
let thickness = thickness.clamp(1.0e-4, 0.5);
let key = (latitude_segments, longitude_segments, thickness.to_bits());
if let Some(handle) = self.wireframe_sphere_meshes.get(&key).copied() {
return handle;
}
let handle = self.register_mesh(MeshFactory::wireframe_sphere(
latitude_segments,
longitude_segments,
thickness,
));
self.wireframe_sphere_meshes.insert(key, handle);
handle
}
pub fn wireframe_icosahedron_mesh(
&mut self,
tessellations: u32,
sphericalness: f32,
thickness: f32,
) -> CpuMeshHandle {
let sphericalness = sphericalness.clamp(0.0, 1.0);
let thickness = thickness.clamp(1.0e-4, 0.5);
let key = (tessellations, sphericalness.to_bits(), thickness.to_bits());
if let Some(handle) = self.wireframe_icosahedron_meshes.get(&key).copied() {
return handle;
}
let handle = self.register_mesh(MeshFactory::wireframe_icosahedron(
tessellations,
sphericalness,
thickness,
));
self.wireframe_icosahedron_meshes.insert(key, handle);
handle
}
pub fn capsule_y_mesh(&mut self, radius: f32, half_segment: f32) -> CpuMeshHandle {
let radius = radius.max(0.0);
let half_segment = half_segment.max(0.0);
let key = (radius.to_bits(), half_segment.to_bits());
if let Some(handle) = self.capsule_y_meshes.get(&key).copied() {
return handle;
}
let handle = self.register_mesh(MeshFactory::capsule_y(radius, half_segment, 32, 12));
self.capsule_y_meshes.insert(key, handle);
handle
}
pub fn register_imported_mesh(
&mut self,
key: impl Into<String>,
mesh: CpuMesh,
) -> CpuMeshHandle {
let key = key.into();
let h = self.register_mesh(mesh);
self.imported_meshes.insert(key, h);
h
}
pub fn imported_mesh(&self, key: &str) -> Option<CpuMeshHandle> {
self.imported_meshes.get(key).copied()
}
pub fn cpu_mesh(&self, h: CpuMeshHandle) -> Option<&CpuMesh> {
self.cpu_meshes.get(h.0 as usize)
}
pub fn cpu_mesh_count(&self) -> usize {
self.cpu_meshes.len()
}
pub fn imported_mesh_count(&self) -> usize {
self.imported_meshes.len()
}
pub fn gpu_mesh_handle(
&mut self,
uploader: &mut dyn MeshUploader,
cpu_mesh: CpuMeshHandle,
) -> Result<MeshHandle, Box<dyn std::error::Error>> {
if let Some(h) = self.gpu_meshes.get(&cpu_mesh).copied() {
return Ok(h);
}
let mesh = self
.cpu_mesh(cpu_mesh)
.ok_or("RenderAssets: invalid CpuMeshHandle")?;
let h = uploader.upload_mesh(mesh)?;
self.gpu_meshes.insert(cpu_mesh, h);
Ok(h)
}
}