use crate::Batch3D;
#[derive(Clone, Debug)]
pub struct Wavefront {
pub vertices: Vec<[f32; 4]>, pub texture_coords: Vec<[f32; 2]>, pub normals: Vec<[f32; 3]>, pub indices: Vec<(usize, usize, usize)>, }
impl Wavefront {
pub fn new(
vertices: Vec<[f32; 4]>,
indices: Vec<(usize, usize, usize)>,
normals: Vec<[f32; 3]>,
texture_coords: Vec<[f32; 2]>,
) -> Self {
Wavefront {
vertices,
indices,
normals,
texture_coords,
}
}
pub fn parse_file(file: String) -> Self {
let contents = std::fs::read_to_string(file).expect("Failed to read the file");
Wavefront::parse_string(contents)
}
pub fn parse_string(contents: String) -> Self {
let lines = contents.lines();
let mut vertices = Vec::new();
let mut normals = Vec::new();
let mut texture_coords = Vec::new();
let mut indices = Vec::new();
for line in lines {
let trimmed = line.trim();
if trimmed.starts_with('#') || trimmed.is_empty() {
continue; }
if trimmed.starts_with("v ") {
let mut items = trimmed.split_ascii_whitespace();
items.next().unwrap(); let x: f32 = items.next().unwrap().parse().unwrap();
let y: f32 = items.next().unwrap().parse().unwrap();
let z: f32 = items.next().unwrap().parse().unwrap();
vertices.push([x, y, z, 1.0]);
} else if trimmed.starts_with("vn ") {
let mut items = trimmed.split_ascii_whitespace();
items.next().unwrap(); let x: f32 = items.next().unwrap().parse().unwrap();
let y: f32 = items.next().unwrap().parse().unwrap();
let z: f32 = items.next().unwrap().parse().unwrap();
normals.push([x, y, z]);
} else if trimmed.starts_with("vt ") {
let mut items = trimmed.split_ascii_whitespace();
items.next().unwrap(); let u: f32 = items.next().unwrap().parse().unwrap();
let v: f32 = items.next().unwrap().parse().unwrap();
texture_coords.push([u, v]);
} else if trimmed.starts_with("f ") {
let mut items = trimmed.split_ascii_whitespace();
items.next().unwrap();
let parse_face = |face_str: &str| -> usize {
let mut parts = face_str.split('/');
parts.next().unwrap().parse::<usize>().unwrap() - 1
};
let v0 = parse_face(items.next().unwrap());
let v1 = parse_face(items.next().unwrap());
let v2 = parse_face(items.next().unwrap());
indices.push((v0, v1, v2));
}
}
Wavefront::new(vertices, indices, normals, texture_coords)
}
pub fn to_batch(self) -> Batch3D {
let uvs = if self.texture_coords.is_empty() {
self.vertices.iter().map(|v| [v[0], v[1]]).collect()
} else {
self.texture_coords
};
Batch3D::new(self.vertices, self.indices, uvs)
}
}