106 lines
3.1 KiB
Rust
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)
|
|
}
|