summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-09-16 17:43:44 +0200
committerHampusM <hampus@hampusmat.com>2026-09-16 17:43:44 +0200
commit99bd0d8e78a2f7739344f2a55e0ae7babd91514b (patch)
treeb6264423e95c3fec1d48ce05537ce71c7c5ecdee
parent047f75917dc963d2ee92cb6d3d3dca1c3aea5854 (diff)
refactor(engine): simplify how model materials are handled
-rw-r--r--engine/src/material/asset.rs16
-rw-r--r--engine/src/model.rs108
-rw-r--r--engine/src/model/asset.rs45
-rw-r--r--engine/src/rendering/main_render_pass.rs2
4 files changed, 45 insertions, 126 deletions
diff --git a/engine/src/material/asset.rs b/engine/src/material/asset.rs
index 31d4ce5..f87b768 100644
--- a/engine/src/material/asset.rs
+++ b/engine/src/material/asset.rs
@@ -37,10 +37,6 @@ fn import_wavefront_mtl_asset(
.map_err(|err| Error::ReadFailed(err, path.to_path_buf()))?,
)?;
- let mut mat_asset_map = Map {
- assets: HashMap::with_capacity(named_materials.len()),
- };
-
for material in named_materials {
let mut material_builder = Material::builder()
.ambient(material.ambient)
@@ -66,19 +62,9 @@ fn import_wavefront_mtl_asset(
);
}
- let material_name = material.name;
- let material = material_builder.build();
-
- let material_asset =
- asset_submitter.submit_store_named(material_name.clone(), material);
-
- mat_asset_map
- .assets
- .insert(material_name.into(), material_asset);
+ asset_submitter.submit_store_named(material.name, material_builder.build());
}
- asset_submitter.submit_store(mat_asset_map);
-
Ok(())
}
diff --git a/engine/src/model.rs b/engine/src/model.rs
index 60a5615..1269afd 100644
--- a/engine/src/model.rs
+++ b/engine/src/model.rs
@@ -1,9 +1,5 @@
-use std::borrow::Cow;
-use std::collections::HashMap;
-
use crate::asset::{Assets, Handle as AssetHandle};
use crate::ecs::Component;
-use crate::material::asset::Map as MaterialAssetMap;
use crate::material::Material;
use crate::mesh::Mesh;
@@ -29,8 +25,7 @@ impl Model
pub struct Spec
{
pub mesh_asset: Option<AssetHandle<Mesh>>,
- pub materials: Materials,
- pub material_names: Vec<Cow<'static, str>>,
+ pub materials: Vec<MaterialDescription>,
}
impl Spec
@@ -45,31 +40,16 @@ impl Spec
assets: &'assets Assets,
) -> MaterialSearchResult<'assets>
{
- let Some(material_name) = self.material_names.first() else {
+ let Some(material_desc) = self.materials.first() else {
return MaterialSearchResult::NoMaterials;
};
- let material_asset = match &self.materials {
- Materials::Maps(material_asset_map_assets) => material_asset_map_assets
- .iter()
- .find_map(|mat_asset_map_asset| {
- let mat_asset_map = assets.get(mat_asset_map_asset)?;
-
- mat_asset_map.assets.get(material_name)
- }),
- Materials::Direct(material_assets) => material_assets.get(material_name),
- };
-
- let Some(material_asset) = material_asset else {
- return MaterialSearchResult::NotFound;
- };
-
- if assets.get(material_asset).is_none() {
+ if assets.get(&material_desc.asset).is_none() {
tracing::trace!("Missing material asset");
return MaterialSearchResult::NotFound;
}
- MaterialSearchResult::Found(material_asset)
+ MaterialSearchResult::Found(&material_desc.asset)
}
}
@@ -77,8 +57,7 @@ impl Spec
pub struct SpecBuilder
{
mesh_asset: Option<AssetHandle<Mesh>>,
- materials: Materials,
- material_names: Vec<Cow<'static, str>>,
+ materials: Vec<MaterialDescription>,
}
impl SpecBuilder
@@ -90,29 +69,12 @@ impl SpecBuilder
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>(
+ pub fn materials(
mut self,
- material_names: impl IntoIterator<Item = MaterialName>,
+ materials: impl IntoIterator<Item = MaterialDescription>,
) -> Self
- where
- MaterialName: Into<Cow<'static, str>>,
{
- self.material_names
- .extend(material_names.into_iter().map(|mat_name| mat_name.into()));
+ self.materials = materials.into_iter().collect();
self
}
@@ -120,67 +82,25 @@ impl SpecBuilder
#[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
+#[non_exhaustive]
+pub struct MaterialDescription
{
- 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(),
- }
- }
+ pub asset: AssetHandle<Material>,
}
-impl Default for Materials
+impl MaterialDescription
{
- fn default() -> Self
+ pub fn new(asset: AssetHandle<Material>) -> Self
{
- Self::Maps(Vec::new())
+ Self { asset }
}
}
diff --git a/engine/src/model/asset.rs b/engine/src/model/asset.rs
index 5487203..52a6733 100644
--- a/engine/src/model/asset.rs
+++ b/engine/src/model/asset.rs
@@ -1,9 +1,11 @@
use std::fs::read_to_string;
use std::path::{Path, PathBuf};
-use crate::asset::{Assets, Submitter as AssetSubmitter};
-use crate::material::asset::Map as MaterialAssetMap;
-use crate::model::{Materials, Spec};
+use ecs::util::Either;
+
+use crate::asset::{Assets, Label as AssetLabel, Submitter as AssetSubmitter};
+use crate::material::Material;
+use crate::model::{MaterialDescription, Spec};
#[derive(Debug, Clone)]
#[non_exhaustive]
@@ -69,24 +71,32 @@ fn import_wavefront_obj_asset(
let mesh_asset = asset_submitter.submit_store_named("mesh", mesh);
- let mut material_asset_map_assets = Vec::with_capacity(obj.mtl_libs.len());
-
- for mtl_lib_path in &obj.mtl_libs {
- let mtl_lib_asset = asset_submitter
- .submit_load_other::<MaterialAssetMap>(parent_path.join(mtl_lib_path));
-
- material_asset_map_assets.push(mtl_lib_asset);
+ if obj.mtl_libs.len() > 1 {
+ return Err(Error::MoreThanOneMaterialLibrary);
}
asset_submitter.submit_store(
Spec::builder()
.mesh(mesh_asset)
- .materials(Materials::Maps(material_asset_map_assets))
- .material_names(
- obj.unique_used_material_names
- .into_iter()
- .map(|material_name| material_name.into_string()),
- )
+ .materials(if obj.mtl_libs.is_empty() {
+ Either::A([].into_iter())
+ } else {
+ Either::B(
+ obj.unique_used_material_names
+ .iter()
+ .zip(std::iter::repeat(obj.mtl_libs.iter()).flatten())
+ .map(|(material_name, mtl_lib)| {
+ MaterialDescription::new(
+ asset_submitter.submit_load_other::<Material>(
+ AssetLabel {
+ path: parent_path.join(mtl_lib).into(),
+ name: Some(material_name.as_ref().into()),
+ },
+ ),
+ )
+ }),
+ )
+ })
.build(),
);
@@ -102,6 +112,9 @@ enum Error
#[error("Failed to read file {}", .1.display())]
ReadFailed(#[source] std::io::Error, PathBuf),
+ #[error("More than one material library is specified. This is not supported")]
+ MoreThanOneMaterialLibrary,
+
#[error(transparent)]
Other(#[from] crate::file_format::wavefront::obj::Error),
}
diff --git a/engine/src/rendering/main_render_pass.rs b/engine/src/rendering/main_render_pass.rs
index 7364024..ce6e040 100644
--- a/engine/src/rendering/main_render_pass.rs
+++ b/engine/src/rendering/main_render_pass.rs
@@ -487,7 +487,7 @@ fn add_renderable_creation_commands(
return;
}
- debug_assert!(model_spec.material_names.len() <= 1);
+ debug_assert!(model_spec.materials.len() <= 1);
let model_material = match model_spec.find_first_material(&assets) {
MaterialSearchResult::Found(model_material_asset) => {