use glam::{vec2, vec3, Vec2, Vec3}; use std::io; #[derive(Copy, Clone, Debug)] struct ObjVertex { vertex: usize, normal: usize, tex_coord: usize, } #[derive(Copy, Clone, Debug)] struct ObjFace { vertices: [ObjVertex; 3], } #[derive(Debug)] struct ObjMesh { vertices: Vec, normals: Vec, tex_coords: Vec, faces: Vec, } impl ObjMesh { fn parse_v2(tokens: &[&str]) -> Vec2 { assert_eq!(tokens.len(), 2); let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); vec2(tokens[0], tokens[1]) } fn parse_v3(tokens: &[&str]) -> Vec3 { assert_eq!(tokens.len(), 3); let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); vec3(tokens[0], tokens[1], tokens[2]) } fn parse_fv(desc: &&str) -> ObjVertex { let tokens: Vec<_> = desc .split('/') .map(|s| s.parse::().unwrap() - 1) .collect(); assert_eq!(tokens.len(), 3); ObjVertex { vertex: tokens[0], tex_coord: tokens[1], normal: tokens[2], } } fn parse_f(tokens: &[&str]) -> ObjFace { let vertices: Vec<_> = tokens.iter().map(ObjMesh::parse_fv).collect(); ObjFace { vertices: vertices.as_slice().try_into().unwrap(), } } fn read(f: &mut impl io::BufRead) -> io::Result { let mut result = ObjMesh { vertices: Vec::new(), normals: Vec::new(), tex_coords: Vec::new(), faces: Vec::new(), }; loop { let mut line = String::new(); if f.read_line(&mut line)? == 0 { break; } let tokens: Vec<&str> = line.trim().split('#').next().unwrap().split(' ').collect(); match tokens[0] { "v" => result.vertices.push(Self::parse_v3(&tokens[1..])), "vn" => result.normals.push(Self::parse_v3(&tokens[1..])), "vt" => result.tex_coords.push(Self::parse_v2(&tokens[1..])), "f" => result.faces.push(Self::parse_f(&tokens[1..])), _ => (), } } Ok(result) } fn flatten(&self) -> Vec { self.faces .iter() .map(|face| Face { vertices: face.vertices.map(|iv| self.vertices[iv.vertex]), normal: self.normals[face.vertices[0].normal], }) .collect() } } #[derive(Copy, Clone, Debug)] pub struct Face { pub vertices: [Vec3; 3], pub normal: Vec3, } pub fn load_mesh(f: &mut impl io::BufRead) -> io::Result> { Ok(ObjMesh::read(f)?.flatten()) }