diff --git a/src/main.rs b/src/main.rs index 8e2db3c..b228c1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +mod mesh_loader; + use std::fs::File; use std::{env, io}; use std::f32::consts::PI; @@ -6,96 +8,7 @@ use std::io::Write; use rand::Rng; use glm; use glm::{dot, ivec2, IVec2, ivec3, to_ivec3, vec2, Vec2, Vec3}; - -#[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(); - glm::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 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)] -struct Face { - vertices: [Vec3; 3], - normal: Vec3, -} +use crate::mesh_loader::load_mesh; const W: i32 = 800; const H: i32 = 600; @@ -171,8 +84,7 @@ fn main() -> io::Result<()> { let mesh = { let f = File::open(&args[1])?; let mut f = BufReader::new(f); - ObjMesh::read(&mut f)? - .flatten() + load_mesh(&mut f)? }; let mut img = Image { w: W, diff --git a/src/mesh_loader.rs b/src/mesh_loader.rs new file mode 100644 index 0000000..ed2e259 --- /dev/null +++ b/src/mesh_loader.rs @@ -0,0 +1,96 @@ +use std::io; +use glm::{vec2, vec3, Vec2, Vec3}; + +#[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()) +}