use std::borrow::Cow; use std::collections::HashMap; use ecs::Component; use crate::asset::Handle as AssetHandle; use crate::material::Material; use crate::material::asset::Map as MaterialAssetMap; use crate::mesh::Mesh; pub mod asset; #[derive(Debug, Clone, Component)] #[non_exhaustive] pub struct Model { pub spec_asset: AssetHandle, } impl Model { pub fn new(asset_handle: AssetHandle) -> Self { Self { spec_asset: asset_handle } } } #[derive(Debug, Clone)] #[non_exhaustive] pub struct Spec { pub mesh_asset: Option>, pub materials: Materials, pub material_names: Vec>, } impl Spec { pub fn builder() -> SpecBuilder { SpecBuilder::default() } } #[derive(Debug, Default, Clone)] pub struct SpecBuilder { mesh_asset: Option>, materials: Materials, material_names: Vec>, } impl SpecBuilder { pub fn mesh(mut self, asset: AssetHandle) -> Self { self.mesh_asset = Some(asset); self } pub fn materials(mut self, materials: Materials) -> Self { self.materials = materials; self } pub fn material_name(mut self, material_name: impl Into>) -> Self { self.material_names.push(material_name.into()); self } pub fn material_names( mut self, material_names: impl IntoIterator, ) -> Self where MaterialName: Into>, { self.material_names .extend(material_names.into_iter().map(|mat_name| mat_name.into())); self } #[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"); } if self.materials.is_empty() && !self.material_names.is_empty() { tracing::warn!("Model spec will have material names but no materials"); } Spec { mesh_asset: self.mesh_asset, materials: self.materials, material_names: self.material_names, } } } #[derive(Debug, Clone)] pub enum Materials { Direct(HashMap, AssetHandle>), Maps(Vec>), } impl Materials { pub fn direct( material_assets: impl IntoIterator)>, ) -> Self where MaterialName: Into>, { Self::Direct( material_assets .into_iter() .map(|(material_name, mat_asset)| (material_name.into(), mat_asset)) .collect(), ) } 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(), } } 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(), } } } impl Default for Materials { fn default() -> Self { Self::Maps(Vec::new()) } }