diff options
| author | HampusM <hampus@hampusmat.com> | 2025-11-06 19:08:01 +0100 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2025-11-06 19:08:01 +0100 |
| commit | c71a7048243148003f9eb09a03ab32dfcf249f9e (patch) | |
| tree | 20d7d7854f353a1f02b65cb517e543e31c37afc1 /engine/src/model.rs | |
| parent | 3e19baab36762b4816301dab591405d3f1561287 (diff) | |
refactor(engine): make models import as multiple asserts
Diffstat (limited to 'engine/src/model.rs')
| -rw-r--r-- | engine/src/model.rs | 202 |
1 files changed, 90 insertions, 112 deletions
diff --git a/engine/src/model.rs b/engine/src/model.rs index 9f5840c..4c88f8f 100644 --- a/engine/src/model.rs +++ b/engine/src/model.rs @@ -1,176 +1,154 @@ use std::borrow::Cow; use std::collections::HashMap; -use std::fs::read_to_string; -use std::path::Path; use ecs::Component; -use crate::asset::{Assets, Handle as AssetHandle, Submitter as AssetSubmitter}; +use crate::asset::Handle as AssetHandle; use crate::material::Material; +use crate::material::asset::Map as MaterialAssetMap; use crate::mesh::Mesh; -use crate::texture::Texture; + +pub mod asset; #[derive(Debug, Clone, Component)] #[non_exhaustive] pub struct Model { - pub asset_handle: AssetHandle<Data>, + pub spec_asset: AssetHandle<Spec>, } impl Model { - pub fn new(asset_handle: AssetHandle<Data>) -> Self + pub fn new(asset_handle: AssetHandle<Spec>) -> Self { - Self { asset_handle } + Self { spec_asset: asset_handle } } } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Clone)] #[non_exhaustive] -pub struct Data +pub struct Spec { - pub mesh: Mesh, - pub materials: HashMap<String, Material>, + pub mesh_asset: Option<AssetHandle<Mesh>>, + pub materials: Materials, + pub material_names: Vec<Cow<'static, str>>, } -impl Data +impl Spec { - pub fn builder() -> DataBuilder + pub fn builder() -> SpecBuilder { - DataBuilder::default() + SpecBuilder::default() } } #[derive(Debug, Default, Clone)] -pub struct DataBuilder +pub struct SpecBuilder { - mesh: Mesh, - materials: HashMap<String, Material>, + mesh_asset: Option<AssetHandle<Mesh>>, + materials: Materials, + material_names: Vec<Cow<'static, str>>, } -impl DataBuilder +impl SpecBuilder { - pub fn mesh(mut self, mesh: Mesh) -> Self + pub fn mesh(mut self, asset: AssetHandle<Mesh>) -> Self { - self.mesh = mesh; + self.mesh_asset = Some(asset); self } - pub fn material<'name>( - mut self, - name: impl Into<Cow<'name, str>>, - material: Material, - ) -> Self + pub fn materials(mut self, materials: Materials) -> Self { - self.materials.insert(name.into().into_owned(), material); + self.materials = materials; self } - pub fn build(self) -> Data + pub fn material_name(mut self, material_name: impl Into<Cow<'static, str>>) -> Self { - Data { - mesh: self.mesh, - materials: self.materials, - } + self.material_names.push(material_name.into()); + + self } -} -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct Settings {} + pub fn material_names<MaterialName>( + mut self, + material_names: impl IntoIterator<Item = MaterialName>, + ) -> Self + where + MaterialName: Into<Cow<'static, str>>, + { + self.material_names + .extend(material_names.into_iter().map(|mat_name| mat_name.into())); -#[derive(Debug, thiserror::Error)] -enum Error -{ - #[error("Failed to read model file")] - ReadModelFileFailed(#[source] std::io::Error), + self + } - #[error("Failed to read material file")] - ReadMaterialFileFailed(#[source] std::io::Error), + #[tracing::instrument(skip_all)] + pub fn build(self) -> Spec + { + if !self.materials.is_empty() && self.material_names.is_empty() { + tracing::warn!("Model spec will have materials but no material names"); + } - #[error("Failed to parse model file")] - ParsingFailed(#[from] ParsingError), -} + if self.materials.is_empty() && !self.material_names.is_empty() { + tracing::warn!("Model spec will have material names but no materials"); + } -pub fn set_asset_importers(assets: &mut Assets) -{ - assets.set_importer(["obj"], import_wavefront_obj_asset); + Spec { + mesh_asset: self.mesh_asset, + materials: self.materials, + material_names: self.material_names, + } + } } -#[derive(Debug, thiserror::Error)] -enum ParsingError +#[derive(Debug, Clone)] +pub enum Materials { - #[error(transparent)] - Obj(#[from] crate::file_format::wavefront::obj::Error), - - #[error(transparent)] - Mtl(#[from] crate::file_format::wavefront::mtl::Error), + Direct(HashMap<Cow<'static, str>, AssetHandle<Material>>), + Maps(Vec<AssetHandle<MaterialAssetMap>>), } -fn import_wavefront_obj_asset( - asset_submitter: &mut AssetSubmitter<'_>, - path: &Path, - _settings: Option<&'_ Settings>, -) -> Result<(), Error> +impl Materials { - let obj = crate::file_format::wavefront::obj::parse( - &read_to_string(path).map_err(Error::ReadModelFileFailed)?, - ) - .map_err(|err| Error::ParsingFailed(ParsingError::Obj(err)))?; - - let mesh = obj - .to_mesh() - .map_err(|err| Error::ParsingFailed(ParsingError::Obj(err)))?; - - let mut materials = - HashMap::<String, Material>::with_capacity(obj.mtl_libs.iter().flatten().count()); - - for mtl_lib_path in obj.mtl_libs.iter().flatten() { - materials.extend(import_mtl(asset_submitter, &mtl_lib_path)?); + pub fn direct<MaterialName>( + material_assets: impl IntoIterator<Item = (MaterialName, AssetHandle<Material>)>, + ) -> Self + where + MaterialName: Into<Cow<'static, str>>, + { + Self::Direct( + material_assets + .into_iter() + .map(|(material_name, mat_asset)| (material_name.into(), mat_asset)) + .collect(), + ) } - asset_submitter.submit_store(Data { mesh, materials }); - - Ok(()) -} - -fn import_mtl<'a>( - asset_submitter: &'a AssetSubmitter<'_>, - path: &Path, -) -> Result<impl Iterator<Item = (String, Material)> + 'a, Error> -{ - let named_materials = crate::file_format::wavefront::mtl::parse( - &read_to_string(path).map_err(Error::ReadMaterialFileFailed)?, - ) - .map_err(|err| Error::ParsingFailed(ParsingError::Mtl(err)))?; - - Ok(named_materials.into_iter().map(|named_material| { - let mut material_builder = Material::builder() - .ambient(named_material.ambient) - .diffuse(named_material.diffuse) - .specular(named_material.specular) - .shininess(named_material.shininess); - - if let Some(ambient_map) = named_material.ambient_map { - material_builder = material_builder.ambient_map(Texture::new( - asset_submitter.submit_load_other(ambient_map.path.as_path()), - )); - } - - if let Some(diffuse_map) = named_material.diffuse_map { - material_builder = material_builder.diffuse_map(Texture::new( - asset_submitter.submit_load_other(diffuse_map.path.as_path()), - )); + pub fn is_empty(&self) -> bool + { + match self { + Self::Direct(material_assets) => material_assets.is_empty(), + Self::Maps(material_asset_map_assets) => material_asset_map_assets.is_empty(), } + } - if let Some(specular_map) = named_material.specular_map { - material_builder = material_builder.specular_map(Texture::new( - asset_submitter.submit_load_other(specular_map.path.as_path()), - )); + pub fn len(&self) -> usize + { + match self { + Self::Direct(material_assets) => material_assets.len(), + Self::Maps(material_asset_map_assets) => material_asset_map_assets.len(), } + } +} - (named_material.name, material_builder.build()) - })) +impl Default for Materials +{ + fn default() -> Self + { + Self::Maps(Vec::new()) + } } |
