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.rs154
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())
+ }
+}