1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
pub mod load;
pub mod mat;
pub mod prelude {
    pub use crate::load::*;
    pub use crate::mat::*;
    pub use crate::*;
}

use crate::load::LoadOptions;
use load::{Loader, MeshDescriptor, SceneDescriptor};
use std::{collections::HashMap, error::Error, fmt::Display, path::PathBuf, write};

#[derive(Debug, Clone)]
pub enum LoadResult {
    /// Reference to single mesh
    Mesh(MeshDescriptor),
    /// Indices of root nodes of scene
    Scene(SceneDescriptor),
    None(LoadError),
}

#[derive(Debug, Clone)]
pub enum LoadError {
    NoFileExtension,
    UnsupportedExtension(String),
    FileDoesNotExist(PathBuf),
    InvalidFile(PathBuf),
    TextureDoesNotExist(PathBuf),
}

impl Display for LoadError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                LoadError::FileDoesNotExist(file) =>
                    format!("File does not exist: {}", file.display()),
                LoadError::TextureDoesNotExist(file) =>
                    format!("Texture does not exist: {}", file.display()),
                LoadError::InvalidFile(file) =>
                    format!("File might be corrupted: {}", file.display()),
                LoadError::NoFileExtension => String::from("No file extension"),
                LoadError::UnsupportedExtension(ext) =>
                    format!("Unsupported file extension: {}", ext),
            }
        )
    }
}

impl Error for LoadError {}

pub struct LoadInstance {
    loaders: HashMap<String, Box<dyn Loader>>,
}

impl LoadInstance {
    pub fn new() -> Self {
        Self {
            loaders: HashMap::new(),
        }
    }

    /// Loads default loaders included with this library
    pub fn with_default(mut self) -> Self {
        let obj_loader = load::obj::ObjLoader::default();
        for f in obj_loader.file_extensions() {
            self.loaders
                .insert(f, Box::new(load::obj::ObjLoader::default()));
        }

        let gltf_loader = load::gltf::GltfLoader::default();
        for f in gltf_loader.file_extensions() {
            self.loaders
                .insert(f, Box::new(load::gltf::GltfLoader::default()));
        }
        self
    }

    /// Adds a loader to this instance
    pub fn with_loader<T: Loader + Sized + Clone + 'static>(mut self, loader: T) -> Self {
        let file_names = loader.file_extensions();
        for f in file_names {
            let f = String::from(f);
            let loader: Box<dyn Loader> = Box::new(loader.clone());
            self.loaders.insert(f, loader);
        }

        self
    }

    /// Loads file given in LoadOptions
    pub fn load(&self, options: LoadOptions) -> LoadResult {
        let ext = match options.path.extension() {
            Some(e) => e,
            None => return LoadResult::None(LoadError::NoFileExtension),
        };

        let ext = ext.to_str().unwrap().to_string();
        if let Some(loader) = self.loaders.get(&ext) {
            loader.load(options)
        } else {
            return LoadResult::None(LoadError::UnsupportedExtension(ext));
        }
    }
}