summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/src/file_format/wavefront/obj.rs67
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
{