use crate::{assets::parser::parse_args, math::{ Vec2, Vec3 }}; use super::types; use super::error::AssetError; pub fn load_obj(path: &str) -> Result { let mut obj_data = types::ObjData::new(); let content = std::fs::read_to_string(path)?; let mut current_name = String::new(); let mut current_mash = types::ObjMesh { name: String::new(), material_name: None, faces: vec![] }; let delim = " "; for (i, line) in content.lines().enumerate() { let i = i + 1; let line = line.trim(); if let Some((prefix, values)) = line.split_once(' ') { match prefix.trim() { "v" => { match parse_args::<3, f32>(values, delim) { Ok(vec) => obj_data.vertices.push(Vec3(vec)), Err(e) => return Err(AssetError::Parse { file: path.to_string(), line: i, source: e, }) } }, "vt" => { match parse_args::<2, f32>(values, delim) { Ok(vec) => obj_data.tex_coords.push(Vec2(vec)), Err(e) => return Err(AssetError::Parse { file: path.to_string(), line: i, source: e, }) } }, "vn" => { match parse_args::<3, f32>(values, delim) { Ok(vec) => obj_data.normals.push(Vec3(vec)), Err(e) => return Err(AssetError::Parse { file: path.to_string(), line: i, source: e, }) } }, "o" | "g" => { current_name = values.to_string(); current_mash.name = current_name.clone(); } "usemtl" => { if !current_mash.faces.is_empty() { obj_data.meshes.push(current_mash); } let material_name = Some(values.to_string()); current_mash = types::ObjMesh { name: current_name.clone(), material_name, faces: vec![] }; }, "mtllib" => { obj_data.material_lib = Some(values.to_string()); } "f" => { let mut current_face = types::ObjFace { indices: vec![] }; let mut line_split = values.split_whitespace(); while let Some(val) = line_split.next() { let face_index: [u32; 3] = parse_args::<3, u32>(val, "/") .map_err(|e| AssetError::Parse { file: path.to_string(), line: i, source: e })?; // OBJ indices are 1-based, convert to 0-based let vertex_index = types::VertexIndex { position: face_index[0] - 1, tex_coord: if face_index[1] != 0 { Some(face_index[1] - 1) } else { None }, normal: if face_index[2] != 0 { Some(face_index[2] - 1) } else { None }, }; current_face.indices.push(vertex_index); } current_mash.faces.push(current_face); } _ => {} } } } if !current_mash.faces.is_empty() { obj_data.meshes.push(current_mash); } Ok(obj_data) }