From d139e19bd287ba340b923136c266a77367b83990 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 18 May 2024 16:57:03 +0200 Subject: refactor(engine): fix clippy lints --- engine/src/file_format/wavefront/obj.rs | 373 ++++++++++++++++++-------------- 1 file changed, 212 insertions(+), 161 deletions(-) (limited to 'engine/src/file_format/wavefront/obj.rs') diff --git a/engine/src/file_format/wavefront/obj.rs b/engine/src/file_format/wavefront/obj.rs index 97e0110..88e6580 100644 --- a/engine/src/file_format/wavefront/obj.rs +++ b/engine/src/file_format/wavefront/obj.rs @@ -9,6 +9,7 @@ use crate::file_format::wavefront::common::{ keyword, parse_statement_line, ParsingError, + Statement, Triplet, }; use crate::mesh::Mesh; @@ -41,161 +42,12 @@ pub fn parse(obj_content: &str) -> Result }) .collect::, _>>()?; - let vertex_positions = statements - .iter() - .filter_map(|(line_no, statement)| { - if statement.keyword != Keyword::V { - return None; - } - - if statement.arguments.len() == 4 { - return Some(Err(Error::UnsupportedArgumentCount { - keyword: statement.keyword.to_string(), - arg_count: statement.arguments.len(), - line_no: *line_no, - })); - } - - if statement.arguments.len() > 4 { - return Some(Err(Error::InvalidArgumentCount { - keyword: statement.keyword.to_string(), - arg_count: statement.arguments.len(), - line_no: *line_no, - })); - } - - let x = try_option!(statement.get_float_arg(0, *line_no)); - let y = try_option!(statement.get_float_arg(1, *line_no)); - let z = try_option!(statement.get_float_arg(2, *line_no)); - - Some(Ok(Vec3 { x, y, z })) - }) - .collect::, Error>>()?; - - let texture_positions = statements - .iter() - .filter_map(|(line_no, statement)| { - if statement.keyword != Keyword::Vt { - return None; - } - - if statement.arguments.len() == 3 { - return Some(Err(Error::UnsupportedArgumentCount { - keyword: statement.keyword.to_string(), - arg_count: statement.arguments.len(), - line_no: *line_no, - })); - } - - if statement.arguments.len() > 3 { - return Some(Err(Error::InvalidArgumentCount { - keyword: statement.keyword.to_string(), - arg_count: statement.arguments.len(), - line_no: *line_no, - })); - } - - let u = try_option!(statement.get_float_arg(0, *line_no)); - let v = try_option!(statement.get_float_arg(1, *line_no)); - - Some(Ok(Vec2 { x: u, y: v })) - }) - .collect::, Error>>()?; - - let vertex_normals = statements - .iter() - .filter_map(|(line_no, statement)| { - if statement.keyword != Keyword::Vn { - return None; - } - - if statement.arguments.len() > 3 { - return Some(Err(Error::InvalidArgumentCount { - keyword: statement.keyword.to_string(), - arg_count: statement.arguments.len(), - line_no: *line_no, - })); - } - - let i = try_option!(statement.get_float_arg(0, *line_no)); - let j = try_option!(statement.get_float_arg(1, *line_no)); - let k = try_option!(statement.get_float_arg(2, *line_no)); - - Some(Ok(Vec3 { x: i, y: j, z: k })) - }) - .collect::, Error>>()?; - - let material_specifiers = statements - .iter() - .filter_map(|(line_no, statement)| { - if statement.keyword != Keyword::Usemtl { - return None; - } - - if statement.arguments.len() > 1 { - return Some(Err(Error::InvalidArgumentCount { - keyword: statement.keyword.to_string(), - arg_count: statement.arguments.len(), - line_no: *line_no, - })); - } - - let material_name = try_option!(statement.get_text_arg(0, *line_no)); - - Some(Ok(MaterialSpecifier { - material_name: material_name.to_string(), - line_no: *line_no, - })) - }) - .collect::, Error>>()?; - - let faces = statements - .iter() - .filter_map(|(line_no, statement)| { - if statement.keyword != Keyword::F { - return None; - } - - if statement.arguments.len() > 3 { - return Some(Err(Error::UnsupportedArgumentCount { - keyword: statement.keyword.to_string(), - arg_count: statement.arguments.len(), - line_no: *line_no, - })); - } - - let vertex_a = try_option!(statement.get_triplet_arg(0, *line_no)).into(); - let vertex_b = try_option!(statement.get_triplet_arg(1, *line_no)).into(); - let vertex_c = try_option!(statement.get_triplet_arg(2, *line_no)).into(); - - let material_name = - find_material_specifier_for_line_no(&material_specifiers, *line_no) - .map(|material_specifier| material_specifier.material_name.clone()); - - Some(Ok(Face { - vertices: [vertex_a, vertex_b, vertex_c], - material_name, - })) - }) - .collect::, Error>>()?; - - let mtl_libs = statements - .iter() - .filter_map(|(line_no, statement)| { - if statement.keyword != Keyword::Mtllib { - return None; - } - - let mtl_lib_paths = try_option!(statement - .arguments - .iter() - .enumerate() - .map(|(index, value)| Ok(PathBuf::from(value.to_text(index, *line_no)?))) - .collect::, ParsingError>>()); - - Some(Ok(mtl_lib_paths)) - }) - .collect::, Error>>()?; + let vertex_positions = get_vertex_positions_from_statements(&statements)?; + let texture_positions = get_texture_positions_from_statements(&statements)?; + let vertex_normals = get_vertex_normals_from_statements(&statements)?; + let material_specs = get_material_specs_from_statements(&statements)?; + let faces = get_faces_from_statements(&statements, &material_specs)?; + let mtl_libs = get_mtl_libs_from_statements(&statements)?; Ok(Obj { vertex_positions, @@ -206,7 +58,7 @@ pub fn parse(obj_content: &str) -> Result }) } -/// The output from parsing the content of a Wavefront `.obj` using [`parse`]. +/// The data of a Wavefront object file. #[derive(Debug)] #[non_exhaustive] pub struct Obj @@ -220,13 +72,20 @@ pub struct Obj impl Obj { + /// Creates a [`Mesh`] from this Wavefront object file data. + /// + /// # Errors + /// Returns `Err` if: + /// - A face's vertex position cannot be found + /// - A face's texture position cannot be found + /// - A face's vertex normal cannot be found + /// - A face index does not fit in a [`u32`] pub fn to_mesh(&self) -> Result { let vertices = self .faces .iter() - .map(|face| face.vertices.clone()) - .flatten() + .flat_map(|face| face.vertices.clone()) .map(|face_vertex| face_vertex.to_vertex(self)) .collect::, Error>>()?; @@ -235,8 +94,7 @@ impl Obj Some( self.faces .iter() - .map(|face| face.vertices.clone()) - .flatten() + .flat_map(|face| face.vertices.clone()) .enumerate() .map(|(index, _)| { u32::try_from(index).map_err(|_| Error::FaceIndexTooBig(index)) @@ -295,6 +153,12 @@ pub struct FaceVertex impl FaceVertex { /// Tries to convert this face vertex into a [`Vertex`]. + /// + /// # Errors + /// Returns `Err` if: + /// - The face's vertex position cannot be found in the given [`Obj`] + /// - The face's texture position cannot be found in the given [`Obj`] + /// - The face's vertex normal cannot be found in the given [`Obj`] pub fn to_vertex(&self, obj: &Obj) -> Result { let mut vertex_builder = VertexBuilder::default(); @@ -313,7 +177,7 @@ impl FaceVertex texture_pos_index: face_vertex_texture, })?; - vertex_builder = vertex_builder.texture_coords(texture_pos.clone()); + vertex_builder = vertex_builder.texture_coords(*texture_pos); } if let Some(face_vertex_normal) = self.normal { @@ -479,6 +343,193 @@ where } } +fn get_vertex_positions_from_statements( + statements: &[(usize, Statement)], +) -> Result>, Error> +{ + statements + .iter() + .filter_map(|(line_no, statement)| { + if statement.keyword != Keyword::V { + return None; + } + + if statement.arguments.len() == 4 { + return Some(Err(Error::UnsupportedArgumentCount { + keyword: statement.keyword.to_string(), + arg_count: statement.arguments.len(), + line_no: *line_no, + })); + } + + if statement.arguments.len() > 4 { + return Some(Err(Error::InvalidArgumentCount { + keyword: statement.keyword.to_string(), + arg_count: statement.arguments.len(), + line_no: *line_no, + })); + } + + let x = try_option!(statement.get_float_arg(0, *line_no)); + let y = try_option!(statement.get_float_arg(1, *line_no)); + let z = try_option!(statement.get_float_arg(2, *line_no)); + + Some(Ok(Vec3 { x, y, z })) + }) + .collect::, Error>>() +} + +fn get_texture_positions_from_statements( + statements: &[(usize, Statement)], +) -> Result>, Error> +{ + statements + .iter() + .filter_map(|(line_no, statement)| { + if statement.keyword != Keyword::Vt { + return None; + } + + if statement.arguments.len() == 3 { + return Some(Err(Error::UnsupportedArgumentCount { + keyword: statement.keyword.to_string(), + arg_count: statement.arguments.len(), + line_no: *line_no, + })); + } + + if statement.arguments.len() > 3 { + return Some(Err(Error::InvalidArgumentCount { + keyword: statement.keyword.to_string(), + arg_count: statement.arguments.len(), + line_no: *line_no, + })); + } + + let u = try_option!(statement.get_float_arg(0, *line_no)); + let v = try_option!(statement.get_float_arg(1, *line_no)); + + Some(Ok(Vec2 { x: u, y: v })) + }) + .collect::, Error>>() +} + +fn get_vertex_normals_from_statements( + statements: &[(usize, Statement)], +) -> Result>, Error> +{ + statements + .iter() + .filter_map(|(line_no, statement)| { + if statement.keyword != Keyword::Vn { + return None; + } + + if statement.arguments.len() > 3 { + return Some(Err(Error::InvalidArgumentCount { + keyword: statement.keyword.to_string(), + arg_count: statement.arguments.len(), + line_no: *line_no, + })); + } + + let i = try_option!(statement.get_float_arg(0, *line_no)); + let j = try_option!(statement.get_float_arg(1, *line_no)); + let k = try_option!(statement.get_float_arg(2, *line_no)); + + Some(Ok(Vec3 { x: i, y: j, z: k })) + }) + .collect::, Error>>() +} + +fn get_material_specs_from_statements( + statements: &[(usize, Statement)], +) -> Result, Error> +{ + statements + .iter() + .filter_map(|(line_no, statement)| { + if statement.keyword != Keyword::Usemtl { + return None; + } + + if statement.arguments.len() > 1 { + return Some(Err(Error::InvalidArgumentCount { + keyword: statement.keyword.to_string(), + arg_count: statement.arguments.len(), + line_no: *line_no, + })); + } + + let material_name = try_option!(statement.get_text_arg(0, *line_no)); + + Some(Ok(MaterialSpecifier { + material_name: material_name.to_string(), + line_no: *line_no, + })) + }) + .collect::, Error>>() +} + +fn get_faces_from_statements( + statements: &[(usize, Statement)], + material_specifiers: &[MaterialSpecifier], +) -> Result, Error> +{ + statements + .iter() + .filter_map(|(line_no, statement)| { + if statement.keyword != Keyword::F { + return None; + } + + if statement.arguments.len() > 3 { + return Some(Err(Error::UnsupportedArgumentCount { + keyword: statement.keyword.to_string(), + arg_count: statement.arguments.len(), + line_no: *line_no, + })); + } + + let vertex_a = try_option!(statement.get_triplet_arg(0, *line_no)).into(); + let vertex_b = try_option!(statement.get_triplet_arg(1, *line_no)).into(); + let vertex_c = try_option!(statement.get_triplet_arg(2, *line_no)).into(); + + let material_name = + find_material_specifier_for_line_no(material_specifiers, *line_no) + .map(|material_specifier| material_specifier.material_name.clone()); + + Some(Ok(Face { + vertices: [vertex_a, vertex_b, vertex_c], + material_name, + })) + }) + .collect::, Error>>() +} + +fn get_mtl_libs_from_statements( + statements: &[(usize, Statement)], +) -> Result>, Error> +{ + statements + .iter() + .filter_map(|(line_no, statement)| { + if statement.keyword != Keyword::Mtllib { + return None; + } + + let mtl_lib_paths = try_option!(statement + .arguments + .iter() + .enumerate() + .map(|(index, value)| Ok(PathBuf::from(value.to_text(index, *line_no)?))) + .collect::, ParsingError>>()); + + Some(Ok(mtl_lib_paths)) + }) + .collect::, Error>>() +} + #[cfg(test)] mod tests { -- cgit v1.2.3-18-g5258