From c733f0fa45de889702b789c057f02a66b72e9a6d Mon Sep 17 00:00:00 2001 From: "Nira M. Patel" <63446721+nirapatelm@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:05:27 -0700 Subject: [PATCH 1/3] remove add() replaced lib.rs with obj.rs --- obj_loader/src/lib.rs | 158 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 147 insertions(+), 11 deletions(-) diff --git a/obj_loader/src/lib.rs b/obj_loader/src/lib.rs index e7eff00..071eacf 100644 --- a/obj_loader/src/lib.rs +++ b/obj_loader/src/lib.rs @@ -1,15 +1,151 @@ -pub mod obj; -pub fn add(left: usize, right: usize) -> usize { - left + right -} +use cimvr_common::render::{Mesh, Vertex}; +// use cimvr_engine_interface::{dbg, prelude::*}; +// use std::{io::Read, str::FromStr}; + +/// Read OBJ lines into the mesh +/// OBJ line specs: https://all3dp.com/1/obj-file-format-3d-printing-cad/ +pub fn obj_lines_to_mesh(obj: &str) -> Mesh { + let mut m = Mesh::new(); + + for line in obj.lines() { + // Split the line by whitespace + let mut line = line.split_whitespace(); + + // Break the first bit off + let (first, mut rest) = (line.next(), line); + + // Which kind of line is it? + match first { + Some("v") => { + // Vertex + // Treat the line as two arrays of 3 elements (x, y, z) coords and perhaps (u, v, w) + let mut parts = [[0.; 3], [1.; 3]]; + + for part in &mut parts { + // Get strings from the rest of the line + // The by_ref() here allows us to keep eating the line on the next loop + for dim in part { + let Some(text) = rest.next() else { break }; + *dim = text.parse().expect("Invalid float"); + } + } + + // Split the parts back up + let [pos, uvw] = parts; + + // Assemble the vertex + m.vertices.push(Vertex { pos, uvw }); + } + Some("l") => { + // Line + // Do the same for indices + let mut indices = [0; 2]; + for dim in &mut indices { + let Some(text) = rest.next() else { break }; + *dim = text.parse().expect("Invalid index"); + + // OBJ files are one-indexed + *dim -= 1; + } + m.indices.extend(indices); + } + Some("vt") => { + // Vertex textures + // We treat this similarly to how we treat a vertex line, but just as + // 1 array of 3 elements: (u,v,w) + // Each vt line will look like: 'vt u v [w]' + let mut uvw = [0.; 3]; + + for dim in &mut uvw { + let Some(text) = rest.next() else { break }; + *dim = text.parse().expect("Invalid float"); + + //*dim -= 1; + } + + // Add to list of vts + // m.vt_indices.extend(uvw); + } + Some("f") => { + // Faces + // At this point all vertices, texture coordinates, vertex normals etc. + // have been declared + // Treat the line as a list of indices to be divided into triangles + // Drawing faces as a triangle fan + + //faces don't just include indices-- they can also include vertex normals (vn) and texture coordinates (vt) + // We have to anticipate that -#[cfg(test)] -mod tests { - use super::*; + // A face must have at least 3 vertices and at most 30. + let mut faces = [0; 3]; + let max_indices = 30; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + // We don't know how many indices will be on a line, so we will just initialize it without a size for now + let mut parsed_line = vec![]; + + // Allocate a collection so we can better manage the indices + // How do we parse through the line AND add it to a mutable array? Use .push()? + // Potentially infitie loops are terrifying. Re evaluate this later + loop { + let Some(text) = rest.next() else { break }; // Refutable pattern match - if nothing left, break + // Index from string to int, check if index exists + // Add the index to the vector + let index_info: Vec<&str> = text.split("/").collect(); // Split and collect-- from v/vt/vn to + + let idx: u32 = index_info[0].parse().expect("Invalid index"); + parsed_line.push(idx - 1); // OBJ files are one-indexed + + // Vertex might also have vt, vn index associated + // Still need to find a way to apply these + if index_info.len() >= 2 { + let vt = index_info[1].parse::().expect("Invalid vt"); + + if index_info.len() == 3 { + let vn = index_info[2].parse::().expect("Invalid vn"); + } + } + + // We don't want a face with more than ten triangles. Break the loop. + // Probably need to produce an error here + if parsed_line.len() > max_indices { + break; + }; + } + + // When we read the entire line, we need to divide the indexes into triangles + // i.e. if we have a face with 5 verts: + // read in [0,1,2] as a triangle, [0,2,3] as another triangle, [0,3,4] as the next triangle + // Delimit first by whitespace -- then need to check for slashes to delimit texture/vertex normals later + + // Will loop through the parsed line and divide them into triangles + let mut i = 0; + while i + 1 < parsed_line.len() { + // For each iteration, while i is less than the size of the parsed line: + // 3 elements will be pushed at a time + // First element will always be the first index in the parsed line + faces[0] = parsed_line[0]; + // Second element will always be the ith index + faces[1] = parsed_line[i]; + // Third element will always be the (i+1)th index + //If there is no third element, return error + faces[2] = parsed_line[i + 1]; + + // Add those indices to be rendered + m.indices.extend(faces); + + // Increment index + i += 1; + } + } + + // Some("vn") => { // Vertex normals + + // }, + + // Ignore the rest + _ => (), + } } + + m } From 9f120ef84fd964e165e867b6cf22ec263ac09158 Mon Sep 17 00:00:00 2001 From: "Nira M. Patel" <63446721+nirapatelm@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:50:35 -0700 Subject: [PATCH 2/3] add vt parsing --- obj_loader/src/lib.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/obj_loader/src/lib.rs b/obj_loader/src/lib.rs index 071eacf..03c7f1d 100644 --- a/obj_loader/src/lib.rs +++ b/obj_loader/src/lib.rs @@ -6,6 +6,7 @@ use cimvr_common::render::{Mesh, Vertex}; /// OBJ line specs: https://all3dp.com/1/obj-file-format-3d-printing-cad/ pub fn obj_lines_to_mesh(obj: &str) -> Mesh { let mut m = Mesh::new(); + let mut tex_coords: Vec<[f32; 3]> = vec![] for line in obj.lines() { // Split the line by whitespace @@ -57,14 +58,14 @@ pub fn obj_lines_to_mesh(obj: &str) -> Mesh { let mut uvw = [0.; 3]; for dim in &mut uvw { - let Some(text) = rest.next() else { break }; - *dim = text.parse().expect("Invalid float"); - - //*dim -= 1; + if let Some(text) = rest.next() { + *dim = text.parse().expect("Invalid float"); + } else { + break; + } } - - // Add to list of vts - // m.vt_indices.extend(uvw); + // Store parsed texture coord + tex_coords.push(uvw); } Some("f") => { // Faces From 6a32865a0ff27d55057802c8bce56fced105dda0 Mon Sep 17 00:00:00 2001 From: "Nira M. Patel" <63446721+nirapatelm@users.noreply.github.com> Date: Tue, 3 Jun 2025 23:18:19 -0700 Subject: [PATCH 3/3] add vertex normal (vn) parsing --- obj_loader/src/lib.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/obj_loader/src/lib.rs b/obj_loader/src/lib.rs index 03c7f1d..07e3cb3 100644 --- a/obj_loader/src/lib.rs +++ b/obj_loader/src/lib.rs @@ -6,7 +6,8 @@ use cimvr_common::render::{Mesh, Vertex}; /// OBJ line specs: https://all3dp.com/1/obj-file-format-3d-printing-cad/ pub fn obj_lines_to_mesh(obj: &str) -> Mesh { let mut m = Mesh::new(); - let mut tex_coords: Vec<[f32; 3]> = vec![] + let mut tex_coords: Vec<[f32; 3]> = vec![]; + let mut normals: Vec<[f32; 3]> = vec![]; for line in obj.lines() { // Split the line by whitespace @@ -139,9 +140,20 @@ pub fn obj_lines_to_mesh(obj: &str) -> Mesh { } } - // Some("vn") => { // Vertex normals - - // }, + Some("vn") => { + // Vertex normals + // Each vn line will look like: 'vn x y z' + // Represents normal vector component at given vertex + // Will get ref in f definition + let mut normal = [0.; 3]; + for dim in &mut normal { + if let Some(text) = rest.next(){ + *dim = text.parse().expect("Invalid float"); + } + } + // Store vn + normals.push(normal); + }, // Ignore the rest _ => (),