use crate::assets::Unresolved;
use crate::material::Material;
use crate::mesh::{MeshData, NoClips, Part, Slot, Vertex};
use crate::{ReliefData, ShadingData, TextureData};
pub(crate) struct NamedMesh {
vertices: Vec<Vertex>,
indices: Vec<u32>,
slots: Vec<NamedSlot>,
}
impl NamedMesh {
pub(crate) fn new(vertices: Vec<Vertex>, indices: Vec<u32>, slots: Vec<NamedSlot>) -> Self {
Self {
vertices,
indices,
slots,
}
}
pub(crate) fn vertices(&self) -> &[Vertex] {
&self.vertices
}
pub(crate) fn indices(&self) -> &[u32] {
&self.indices
}
pub(crate) fn resolved<P: Part>(
&self,
asset: &str,
) -> Result<MeshData<P, NoClips>, Vec<Unresolved>> {
let slots = self.parts::<P>(asset)?;
Ok(MeshData::resolved(
self.vertices.clone(),
self.indices.clone(),
slots,
))
}
pub(crate) fn parts<P: Part>(&self, asset: &str) -> Result<Vec<Slot>, Vec<Unresolved>> {
let parts: Vec<Option<P>> = self
.slots
.iter()
.map(|slot| P::from_name(&slot.name))
.collect();
let wrong: Vec<Unresolved> = P::all()
.into_iter()
.filter_map(|part| {
let named: Vec<&str> = parts
.iter()
.zip(&self.slots)
.filter(|(resolved, _)| resolved.as_ref() == Some(&part))
.map(|(_, slot)| slot.name.as_str())
.collect();
match named[..] {
[_] => None,
[] => Some(Unresolved::PartUnnamed {
asset: asset.to_owned(),
part: format!("{part:?}"),
}),
[first, second, ..] => Some(Unresolved::PartTwice {
asset: asset.to_owned(),
part: format!("{part:?}"),
first: first.to_owned(),
second: second.to_owned(),
}),
}
})
.collect();
if !wrong.is_empty() {
return Err(wrong);
}
Ok(parts
.into_iter()
.zip(&self.slots)
.map(|(part, slot)| slot.keyed(part.map(|part| part.index())))
.collect())
}
}
pub(crate) struct NamedSlot {
pub(crate) name: String,
pub(crate) index_count: u32,
pub(crate) material: Material,
pub(crate) texture: Option<TextureData>,
pub(crate) relief: Option<ReliefData>,
pub(crate) shading: Option<ShadingData>,
pub(crate) emissive: Option<TextureData>,
}
impl NamedSlot {
fn keyed(&self, part: Option<u32>) -> Slot {
let mut slot = Slot::new(self.index_count, self.material);
if let Some(part) = part {
slot = slot.named(part);
}
if let Some(texture) = self.texture.clone() {
slot = slot.textured(texture);
}
if let Some(relief) = self.relief.clone() {
slot = slot.relief(relief);
}
if let Some(shading) = self.shading.clone() {
slot = slot.shading(shading);
}
if let Some(emissive) = self.emissive.clone() {
slot = slot.emissive_map(emissive);
}
slot
}
}