diff options
Diffstat (limited to 'engine/src/file_format/wavefront/obj.rs')
-rw-r--r-- | engine/src/file_format/wavefront/obj.rs | 67 |
1 files changed, 67 insertions, 0 deletions
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: <https://paulbourke.net/dataformats/obj> +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<ParsedMaterial, ParseError>( + &self, + parse_material_lib: impl Fn(&str) -> Result<Vec<ParsedMaterial>, ParseError>, + ) -> Result<Vec<ParsedMaterial>, MaterialLibsError<ParseError>> + { + 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::<Result<Vec<_>, _>>() + } } #[derive(Debug)] @@ -365,6 +395,21 @@ pub enum Error }, } +#[derive(Debug, thiserror::Error)] +pub enum MaterialLibsError<MaterialLibParseError> +{ + #[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<ValA, ValB> +{ + A(ValA), + B(ValB), +} + +impl<ValA, ValB, Item> Iterator for Either<ValA, ValB> +where + ValA: Iterator<Item = Item>, + ValB: Iterator<Item = Item>, +{ + type Item = Item; + + fn next(&mut self) -> Option<Self::Item> + { + match self { + Self::A(iter_a) => iter_a.next(), + Self::B(iter_b) => iter_b.next(), + } + } +} + #[cfg(test)] mod tests { |