truck_polymesh/
obj.rs

1use crate::*;
2use std::io::{BufRead, BufReader, BufWriter, Read, Write};
3type Vertex = StandardVertex;
4type Result<T> = std::result::Result<T, errors::Error>;
5
6/// Writes obj data to output stream
7/// # Examples
8/// ```
9/// use truck_polymesh::*;
10/// let positions = vec![
11///     Point3::new(0.0, 0.0, 0.0),
12///     Point3::new(1.0, 0.0, 0.0),
13///     Point3::new(0.0, 1.0, 0.0),
14///     Point3::new(0.0, 0.0, 1.0),
15///     Point3::new(1.0, 1.0, 0.0),
16///     Point3::new(1.0, 0.0, 1.0),
17///     Point3::new(0.0, 1.0, 1.0),
18///     Point3::new(1.0, 1.0, 1.0),
19/// ];
20/// let normals = vec![
21///     Vector3::new(1.0, 0.0, 0.0),
22///     Vector3::new(0.0, 1.0, 0.0),
23///     Vector3::new(0.0, 0.0, 1.0),
24///     Vector3::new(-1.0, 0.0, 0.0),
25///     Vector3::new(0.0, -1.0, 0.0),
26///     Vector3::new(0.0, 0.0, -1.0),
27/// ];
28/// let faces = Faces::from_iter(&[
29///     [(0, None, Some(5)), (1, None, Some(5)), (2, None, Some(5))],
30///     [(4, None,Some(5)), (2, None, Some(5)), (1, None, Some(5))],
31///     [(1, None, Some(4)), (0, None, Some(4)), (3, None, Some(4))],
32///     [(1, None, Some(4)), (3, None, Some(4)), (5, None, Some(4))],
33///     [(1, None, Some(0)), (5, None, Some(0)), (4, None, Some(0))],
34///     [(4, None, Some(0)), (5, None, Some(0)), (7, None, Some(0))],
35///     [(2, None, Some(1)), (4, None, Some(1)), (7, None, Some(1))],
36///     [(2, None, Some(1)), (7, None, Some(1)), (6, None, Some(1))],
37///     [(0, None, Some(3)), (2, None, Some(3)), (6, None, Some(3))],
38///     [(0, None, Some(3)), (6, None, Some(3)), (3, None, Some(3))],
39///     [(3, None, Some(2)), (6, None, Some(2)), (7, None, Some(2))],
40///     [(3, None, Some(2)), (7, None, Some(2)), (5, None, Some(2))],
41/// ]);
42/// let mesh = PolygonMesh::new(
43///     StandardAttributes {
44///         positions,
45///         normals,
46///         ..Default::default()
47///     },
48///     faces,
49/// );
50/// obj::write(&mesh, std::fs::File::create("meshdata.obj").unwrap());
51/// ```
52pub fn write<W: Write>(mesh: &PolygonMesh, writer: W) -> Result<()> {
53    sub_write(mesh, &mut BufWriter::new(writer))
54}
55
56/// Writes obj data to output stream
57pub fn write_vec<W: Write>(mesh: &[PolygonMesh], writer: W) -> Result<()> {
58    let mut writer = BufWriter::new(writer);
59    for (i, mesh) in mesh.iter().enumerate() {
60        writer.write_fmt(format_args!("g {i}\n"))?;
61        sub_write(mesh, &mut writer)?;
62    }
63    Ok(())
64}
65
66fn write2vec<V: std::ops::Index<usize, Output = f64>, W: Write>(
67    writer: &mut BufWriter<W>,
68    vecs: &[V],
69    prefix: &str,
70) -> Result<()> {
71    for vec in vecs {
72        writer.write_fmt(format_args!("{} {:.10e} {:.10e}\n", prefix, vec[0], vec[1]))?;
73    }
74    Ok(())
75}
76
77fn write3vec<V: std::ops::Index<usize, Output = f64>, W: Write>(
78    writer: &mut BufWriter<W>,
79    vecs: &[V],
80    prefix: &str,
81) -> Result<()> {
82    for vec in vecs {
83        writer.write_fmt(format_args!(
84            "{} {:.10e} {:.10e} {:.10e}\n",
85            prefix, vec[0], vec[1], vec[2]
86        ))?;
87    }
88    Ok(())
89}
90
91impl Vertex {
92    fn write<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
93        match (self.uv, self.nor) {
94            (None, None) => writer.write_fmt(format_args!("{}", self.pos + 1)),
95            (Some(uv), None) => writer.write_fmt(format_args!("{}/{}", self.pos + 1, uv + 1)),
96            (None, Some(nor)) => writer.write_fmt(format_args!("{}//{}", self.pos + 1, nor + 1)),
97            (Some(uv), Some(nor)) => {
98                writer.write_fmt(format_args!("{}/{}/{}", self.pos + 1, uv + 1, nor + 1))
99            }
100        }
101    }
102}
103
104impl Faces {
105    fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
106        for face in self.face_iter() {
107            writer.write_all(b"f")?;
108            for v in face {
109                writer.write_all(b" ")?;
110                v.write(writer)?;
111            }
112            writer.write_all(b"\n")?;
113        }
114        Ok(())
115    }
116}
117
118fn sub_write<W: Write>(mesh: &PolygonMesh, writer: &mut BufWriter<W>) -> Result<()> {
119    write3vec(writer, mesh.positions(), "v")?;
120    write2vec(writer, mesh.uv_coords(), "vt")?;
121    write3vec(writer, mesh.normals(), "vn")?;
122    mesh.faces.write(writer)
123}
124
125/// Reads mesh data from wavefront obj file.
126pub fn read<R: Read>(reader: R) -> Result<PolygonMesh> {
127    let mut positions = Vec::new();
128    let mut uv_coords = Vec::new();
129    let mut normals = Vec::new();
130    let mut faces = Faces::default();
131    let reader = BufReader::new(reader);
132    for line in reader.lines().map(|s| s.unwrap()) {
133        let mut args = line.split_whitespace();
134        if let Some(first_str) = args.next() {
135            if first_str == "v" {
136                let x = args.next().unwrap().parse::<f64>()?;
137                let y = args.next().unwrap().parse::<f64>()?;
138                let z = args.next().unwrap().parse::<f64>()?;
139                positions.push(Point3::new(x, y, z));
140            } else if first_str == "vt" {
141                let u = args.next().unwrap().parse::<f64>()?;
142                let v = args.next().unwrap().parse::<f64>()?;
143                uv_coords.push(Vector2::new(u, v));
144            } else if first_str == "vn" {
145                let x = args.next().unwrap().parse::<f64>()?;
146                let y = args.next().unwrap().parse::<f64>()?;
147                let z = args.next().unwrap().parse::<f64>()?;
148                normals.push(Vector3::new(x, y, z));
149            } else if first_str == "f" {
150                let mut face = Vec::new();
151                for vert_str in args {
152                    if &vert_str[0..1] == "#" {
153                        break;
154                    }
155                    let mut iter = vert_str.split('/');
156                    let pos = iter
157                        .next()
158                        .map(|val| val.parse::<usize>().map(|i| i - 1).ok())
159                        .unwrap_or(None);
160                    let uv = iter
161                        .next()
162                        .map(|val| val.parse::<usize>().map(|i| i - 1).ok())
163                        .unwrap_or(None);
164                    let nor = iter
165                        .next()
166                        .map(|val| val.parse::<usize>().map(|i| i - 1).ok())
167                        .unwrap_or(None);
168                    let vert = match (pos, uv, nor) {
169                        (None, _, _) => continue,
170                        (Some(pos), uv, nor) => Vertex { pos, uv, nor },
171                    };
172                    face.push(vert);
173                }
174                faces.push(face);
175            }
176        }
177    }
178    PolygonMesh::try_new(
179        StandardAttributes {
180            positions,
181            uv_coords,
182            normals,
183        },
184        faces,
185    )
186}