From 9ce344220ec7d03ec2902907aa41f126faf84df0 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 18 May 2024 15:11:38 +0200 Subject: feat(engine): add Obj method to read & parse it's material libs --- engine/src/file_format/wavefront/obj.rs | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'engine') diff --git a/engine/src/file_format/wavefront/obj.rs b/engine/src/file_format/wavefront/obj.rs index 4df5fe5..6367ead 100644 --- a/engine/src/file_format/wavefront/obj.rs +++ b/engine/src/file_format/wavefront/obj.rs @@ -2,6 +2,7 @@ //! //! File format documentation: +use std::fs::read_to_string; use std::path::PathBuf; use crate::file_format::wavefront::common::{ @@ -244,6 +245,35 @@ impl Obj ), )) } + + /// Reads and parses the material libraries of this `Obj`. + /// + /// # Errors + /// Returns `Err` if: + /// - Reading the contents of a material library fails + /// - Parsing a material library fails + pub fn read_and_parse_material_libs( + &self, + parse_material_lib: impl Fn(&str) -> Result, ParseError>, + ) -> Result, MaterialLibsError> + { + self.mtl_libs + .iter() + .flatten() + .map(|mtl_lib| { + Ok(parse_material_lib(&read_to_string(mtl_lib).map_err( + |err| MaterialLibsError::ReadingMaterialLibFailed { + source: err, + material_lib: mtl_lib.clone(), + }, + )?)?) + }) + .flat_map(|res| match res { + Ok(inner) => Either::A(inner.into_iter().map(Ok)), + Err(err) => Either::B(vec![Err(err)].into_iter()), + }) + .collect::, _>>() + } } #[derive(Debug)] @@ -365,6 +395,21 @@ pub enum Error }, } +#[derive(Debug, thiserror::Error)] +pub enum MaterialLibsError +{ + #[error("Parsing material library failed")] + ParsingFailed(#[from] MaterialLibParseError), + + #[error("Failed to read material library {}", material_lib.display())] + ReadingMaterialLibFailed + { + #[source] + source: std::io::Error, + material_lib: PathBuf, + }, +} + keyword! { #[derive(Debug, PartialEq, Eq, Clone, Copy)] enum Keyword { @@ -412,6 +457,28 @@ fn find_material_specifier_for_line_no( .find(|material_specifier| material_specifier.line_no < line_no) } +enum Either +{ + A(ValA), + B(ValB), +} + +impl Iterator for Either +where + ValA: Iterator, + ValB: Iterator, +{ + type Item = Item; + + fn next(&mut self) -> Option + { + match self { + Self::A(iter_a) => iter_a.next(), + Self::B(iter_b) => iter_b.next(), + } + } +} + #[cfg(test)] mod tests { -- cgit v1.2.3-18-g5258