1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Wavefront file handling.

use crate::{
    err::Error,
    file::Load,
    geom::{Mesh, SmoothTriangle},
    math::{Dir3, Pos3, Vec3},
};
use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::Path,
};

impl Load for Mesh {
    #[inline]
    fn load(path: &Path) -> Result<Self, Error> {
        println!("loading: {}", path.display());
        let vertex_lines: Vec<_> = BufReader::new(File::open(path)?)
            .lines()
            .map(Result::unwrap)
            .filter(|line| line.starts_with("v "))
            .collect();

        let mut verts = Vec::with_capacity(vertex_lines.len());
        for line in vertex_lines {
            let mut words = line.split_whitespace();
            words.next();

            let px = words.next().ok_or("Missing vertex word.")?.parse::<f64>()?;
            let py = words.next().ok_or("Missing vertex word.")?.parse::<f64>()?;
            let pz = words.next().ok_or("Missing vertex word.")?.parse::<f64>()?;

            verts.push(Pos3::new(px, py, pz));
        }

        let normal_lines: Vec<_> = BufReader::new(File::open(path)?)
            .lines()
            .map(Result::unwrap)
            .filter(|line| line.starts_with("vn "))
            .collect();

        let mut norms = Vec::with_capacity(normal_lines.len());
        for line in normal_lines {
            let mut words = line.split_whitespace();
            words.next();

            let nx = words.next().ok_or("Missing normal word.")?.parse::<f64>()?;
            let ny = words.next().ok_or("Missing normal word.")?.parse::<f64>()?;
            let nz = words.next().ok_or("Missing normal word.")?.parse::<f64>()?;

            norms.push(Dir3::new_normalize(Vec3::new(nx, ny, nz)));
        }

        let face_lines: Vec<_> = BufReader::new(File::open(path)?)
            .lines()
            .map(Result::unwrap)
            .filter(|line| line.starts_with("f "))
            .collect();

        let mut faces = Vec::with_capacity(face_lines.len());
        for line in face_lines {
            let line = line.replace("//", " ");
            let mut words = line.split_whitespace();
            words.next();

            let fx = words.next().ok_or("Missing face word.")?.parse::<usize>()? - 1;
            let nx = words
                .next()
                .ok_or("Missing normal word.")?
                .parse::<usize>()?
                - 1;
            let fy = words.next().ok_or("Missing face word.")?.parse::<usize>()? - 1;
            let ny = words
                .next()
                .ok_or("Missing normal word.")?
                .parse::<usize>()?
                - 1;
            let fz = words.next().ok_or("Missing face word.")?.parse::<usize>()? - 1;
            let nz = words
                .next()
                .ok_or("Missing normal word.")?
                .parse::<usize>()?
                - 1;

            faces.push(((fx, fy, fz), (nx, ny, nz)));
        }

        let mut tris = Vec::with_capacity(faces.len());
        for face in faces {
            tris.push(SmoothTriangle::new_from_verts(
                [verts[(face.0).0], verts[(face.0).1], verts[(face.0).2]],
                [norms[(face.1).0], norms[(face.1).1], norms[(face.1).2]],
            ));
        }

        Ok(Self::new(tris))
    }
}