Skip to main content

ursus_core/assets/
loader_registry.rs

1use crate::assets::mesh::CpuMesh;
2use crate::render::gfx::types::Format;
3use std::path::Path;
4use std::sync::Arc;
5
6pub struct LoadedTexture {
7    pub pixels: Vec<u8>,
8    pub width: u32,
9    pub height: u32,
10    pub format: Format,
11}
12
13pub struct LoadedPrimitive {
14    pub mesh: CpuMesh,
15    pub node_translation: [f32; 3],
16    pub node_rotation: [f32; 4],
17    pub node_scale: [f32; 3],
18}
19
20pub struct LoadedMeshSource {
21    pub primitives: Vec<LoadedPrimitive>,
22}
23
24pub trait AssetLoader: Send + Sync {
25    fn extensions(&self) -> &[&str];
26    fn load(&self, path: &Path) -> anyhow::Result<LoadedMeshSource>;
27    fn name(&self) -> &str {
28        "unnamed loader"
29    }
30}
31
32#[derive(Default)]
33pub struct LoaderRegistry {
34    loaders: Vec<Arc<dyn AssetLoader>>,
35}
36
37impl LoaderRegistry {
38    pub fn new() -> Self {
39        Self::default()
40    }
41
42    pub fn register(&mut self, loader: impl AssetLoader + 'static) {
43        self.register_arc(Arc::new(loader));
44    }
45
46    pub fn register_arc(&mut self, loader: Arc<dyn AssetLoader>) {
47        for ext in loader.extensions() {
48            if let Some(existing) = self.find(ext) {
49                if existing.name() == loader.name() {
50                    return;
51                }
52                log::warn!(
53                    "LoaderRegistry: расширение '{}' уже обрабатывается '{}', переопределяется '{}'",
54                    ext,
55                    existing.name(),
56                    loader.name()
57                );
58            }
59        }
60        self.loaders.push(loader);
61    }
62
63    fn find(&self, ext: &str) -> Option<&Arc<dyn AssetLoader>> {
64        self.loaders.iter().rev().find(|l| l.extensions().contains(&ext))
65    }
66
67    pub fn load(&self, path: &Path) -> anyhow::Result<LoadedMeshSource> {
68        let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("").to_lowercase();
69        let loader = self.find(&ext).ok_or_else(|| {
70            anyhow::anyhow!("нет зарегистрированного загрузчика для расширения '.{}': {:?}", ext, path)
71        })?;
72        loader.load(path)
73    }
74
75    pub fn into_loaders(self) -> Vec<Arc<dyn AssetLoader>> {
76        self.loaders
77    }
78}