diff options
Diffstat (limited to 'engine/src/model.rs')
| -rw-r--r-- | engine/src/model.rs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/engine/src/model.rs b/engine/src/model.rs new file mode 100644 index 0000000..4c88f8f --- /dev/null +++ b/engine/src/model.rs @@ -0,0 +1,154 @@ +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<Spec>, +} + +impl Model +{ + pub fn new(asset_handle: AssetHandle<Spec>) -> Self + { + Self { spec_asset: asset_handle } + } +} + +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct Spec +{ + pub mesh_asset: Option<AssetHandle<Mesh>>, + pub materials: Materials, + pub material_names: Vec<Cow<'static, str>>, +} + +impl Spec +{ + pub fn builder() -> SpecBuilder + { + SpecBuilder::default() + } +} + +#[derive(Debug, Default, Clone)] +pub struct SpecBuilder +{ + mesh_asset: Option<AssetHandle<Mesh>>, + materials: Materials, + material_names: Vec<Cow<'static, str>>, +} + +impl SpecBuilder +{ + pub fn mesh(mut self, asset: AssetHandle<Mesh>) -> 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<Cow<'static, str>>) -> Self + { + self.material_names.push(material_name.into()); + + self + } + + 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())); + + 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<Cow<'static, str>, AssetHandle<Material>>), + Maps(Vec<AssetHandle<MaterialAssetMap>>), +} + +impl Materials +{ + 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(), + ) + } + + 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()) + } +} |
