106 lines
3.1 KiB
Rust

use crate::{assets::parser::parse_args, math::{ Vec2, Vec3 }};
use super::types;
use super::error::AssetError;
pub fn load_obj(path: &str) -> Result<types::ObjData, AssetError> {
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)
}