summaryrefslogtreecommitdiff
path: root/engine/src/model.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/model.rs')
-rw-r--r--engine/src/model.rs202
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())
+ }
}