diff options
Diffstat (limited to 'engine/src/file_format/wavefront/obj.rs')
| -rw-r--r-- | engine/src/file_format/wavefront/obj.rs | 171 |
1 files changed, 109 insertions, 62 deletions
diff --git a/engine/src/file_format/wavefront/obj.rs b/engine/src/file_format/wavefront/obj.rs index 88d566c..446903c 100644 --- a/engine/src/file_format/wavefront/obj.rs +++ b/engine/src/file_format/wavefront/obj.rs @@ -7,13 +7,18 @@ use std::fs::read_to_string; use std::path::PathBuf; use crate::file_format::wavefront::common::{ - keyword, - parse_statement_line, ParsingError, Statement, Triplet, + keyword, + parse_statement_line, +}; +use crate::mesh::vertex_buffer::{ + NamedVertexAttr, + VertexAttrInfo, + VertexBuffer as MeshVertexBuffer, }; -use crate::mesh::{Mesh, Vertex}; +use crate::mesh::{Mesh, POSITION_VERTEX_ATTRIB_NAME, VertexAttrType}; use crate::util::try_option; use crate::vector::{Vec2, Vec3}; @@ -82,7 +87,24 @@ impl Obj /// - A face index does not fit in a [`u32`] pub fn to_mesh(&self) -> Result<Mesh, Error> { - let mut vertices = Vec::<Vertex>::with_capacity(self.faces.len() * 3); + let mut vertex_buf = MeshVertexBuffer::with_capacity( + &[ + VertexAttrInfo { + name: POSITION_VERTEX_ATTRIB_NAME.into(), + ty: VertexAttrType::Float32Array { length: 3 }, + }, + VertexAttrInfo { + name: "texture_coords".into(), + ty: VertexAttrType::Float32Array { length: 2 }, + }, + VertexAttrInfo { + name: "normal".into(), + ty: VertexAttrType::Float32Array { length: 3 }, + }, + ], + self.faces.len() * 3, + ); + let mut indices = Vec::<u32>::with_capacity(self.faces.len() * 3); let mut added_face_vertices = @@ -96,10 +118,75 @@ impl Obj continue; } - vertices.push(face_vertex.to_vertex(self)?); + let pos = self + .vertex_positions + .get(face_vertex.position as usize - 1) + .ok_or(Error::FaceVertexPositionNotFound { + vertex_pos_index: face_vertex.position, + })? + .clone(); + + let texture_pos = face_vertex.texture.map_or_else( + || { + if !self.texture_positions.is_empty() { + tracing::warn!(concat!( + "Wavefront OBJ has texture coordinates ", + "but face vertex does not specify one" + )); + } + + Ok(Vec2::default()) + }, + |face_vertex_texture| { + self.texture_positions + .get(face_vertex_texture as usize - 1) + .ok_or(Error::FaceTexturePositionNotFound { + texture_pos_index: face_vertex_texture, + }) + .cloned() + }, + )?; + + let normal = face_vertex.normal.map_or_else( + || { + if !self.vertex_normals.is_empty() { + tracing::warn!(concat!( + "Wavefront OBJ has normals ", + "but face vertex does not specify one" + )); + } + + Ok(Vec3::default()) + }, + |face_vertex_normal| { + self.vertex_normals + .get(face_vertex_normal as usize - 1) + .ok_or(Error::FaceVertexNormalNotFound { + vertex_normal_index: face_vertex_normal, + }) + .cloned() + }, + )?; + + vertex_buf.push(( + NamedVertexAttr { + name: POSITION_VERTEX_ATTRIB_NAME, + value: pos.into_array(), + }, + NamedVertexAttr { + name: "texture_coords", + value: texture_pos.into_array(), + }, + NamedVertexAttr { + name: "normal", + value: normal.into_array(), + }, + )); + + let vertex_index = vertex_buf.len() - 1; - let vertex_index = u32::try_from(vertices.len() - 1) - .map_err(|_| Error::FaceIndexTooBig(vertices.len() - 1))?; + let vertex_index = u32::try_from(vertex_index) + .map_err(|_| Error::FaceIndexTooBig(vertex_index))?; indices.push(vertex_index); @@ -107,7 +194,10 @@ impl Obj } } - Ok(Mesh::new(vertices, Some(indices))) + Ok(Mesh::builder() + .vertices(vertex_buf) + .indices(indices) + .build()) } /// Reads and parses the material libraries of this `Obj`. @@ -156,51 +246,6 @@ pub struct FaceVertex pub normal: Option<u32>, } -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<Vertex, Error> - { - let mut vertex_builder = Vertex::builder(); - - let vertex_pos = *obj.vertex_positions.get(self.position as usize - 1).ok_or( - Error::FaceVertexPositionNotFound { vertex_pos_index: self.position }, - )?; - - vertex_builder = vertex_builder.pos(vertex_pos); - - if let Some(face_vertex_texture) = self.texture { - let texture_pos = obj - .texture_positions - .get(face_vertex_texture as usize - 1) - .ok_or(Error::FaceTexturePositionNotFound { - texture_pos_index: face_vertex_texture, - })?; - - vertex_builder = vertex_builder.texture_coords(*texture_pos); - } - - if let Some(face_vertex_normal) = self.normal { - let vertex_normal = *obj - .vertex_normals - .get(face_vertex_normal as usize - 1) - .ok_or(Error::FaceVertexNormalNotFound { - vertex_normal_index: face_vertex_normal, - })?; - - vertex_builder = vertex_builder.normal(vertex_normal); - } - - Ok(vertex_builder.build()) - } -} - impl From<Triplet> for FaceVertex { fn from(triplet: Triplet) -> Self @@ -219,9 +264,7 @@ pub enum Error #[error(transparent)] ParsingError(#[from] ParsingError), - #[error( - "Face vertex position with index {vertex_pos_index} (1-based) was not found" - )] + #[error("Face vertex position with index {vertex_pos_index} (1-based) was not found")] FaceVertexPositionNotFound { vertex_pos_index: u32 @@ -524,12 +567,16 @@ fn get_mtl_libs_from_statements( 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::<Result<Vec<_>, ParsingError>>()); + let mtl_lib_paths = try_option!( + statement + .arguments + .iter() + .enumerate() + .map(|(index, value)| Ok(PathBuf::from( + value.to_text(index, *line_no)? + ))) + .collect::<Result<Vec<_>, ParsingError>>() + ); Some(Ok(mtl_lib_paths)) }) |
