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