nom_obj/parser/
obj.rs

1/// http://paulbourke.net/dataformats/obj/
2///
3use parser::common::*;
4
5use std::str;
6
7use std::io::BufRead;
8
9#[derive(PartialEq, Debug)]
10pub struct FaceIndex(pub u32, pub Option<u32>, pub Option<u32>);
11
12#[derive(PartialEq, Debug)]
13pub enum ObjLine {
14    Comment(String),
15    ObjectName(String),
16    GroupName(String),
17    MtlLib(String),
18    UseMtl(String),
19    SmoothShading(String),
20    Vertex(f32, f32, f32, Option<f32>), // x, y, z, then w defaults to 1.0
21    VertexParam(f32, f32, f32),
22    Normal(f32, f32, f32),
23    Face(FaceIndex, FaceIndex, FaceIndex),
24    TextureUVW(f32, f32, Option<f32>), // u,v, then w defaults to 0.0
25}
26
27def_string_line!(object_line, "o", ObjLine, ObjectName);
28def_string_line!(group_line, "g", ObjLine, GroupName);
29def_string_line!(mtllib_line, "mtllib", ObjLine, MtlLib);
30def_string_line!(usemtl_line, "usemtl", ObjLine, UseMtl);
31def_string_line!(s_line, "s", ObjLine, SmoothShading);
32
33named!( vertex_line< &[u8], ObjLine >, map!(
34    sp!( delimited!( tag!("v"), float_triple_opt_4th, end_of_line )),
35    |(x,y,z,w)| ObjLine::Vertex(x,y,z,w)
36));
37
38named!( normal_line< &[u8], ObjLine >, map!(
39    sp!( delimited!( tag!("vn"), float_triple, end_of_line )),
40    |(x,y,z)| ObjLine::Normal(x,y,z)
41));
42
43named!( texcoord_line< &[u8], ObjLine >, map!(
44    sp!( delimited!( tag!("vt"), float_pair_opt_3rd, end_of_line )),
45    |(u,v,w)| ObjLine::TextureUVW(u,v,w)
46));
47
48named!( vertex_param_line< &[u8], ObjLine >, map!(
49    sp!(delimited!( tag!("vp"), float_triple, end_of_line )),
50    |(x,y,z)| ObjLine::VertexParam(x,y,z)
51));
52
53named!( face_triple< &[u8], FaceIndex >, map!(
54    tuple!(
55        uint,
56        delimited!( tag!("/"), opt!(uint), tag!("/") ),
57        opt!(uint)
58    ),
59    |(v, vt, vn)| FaceIndex(v, vt, vn)
60));
61
62named!( face_pair< &[u8], FaceIndex >, map!(
63    separated_pair!(
64        uint,
65        tag!("/"),
66        opt!(uint)
67    ),
68    |(v,vt)| FaceIndex(v, vt, None)
69));
70
71named!( face_line< &[u8], ObjLine >, delimited!(
72        sp!(tag!("f")),
73        alt!(
74            sp!(tuple!(uint, uint, uint)) => {|(u1,u2,u3)| ObjLine::Face(
75                FaceIndex(u1, None, None),
76                FaceIndex(u2, None, None),
77                FaceIndex(u3, None, None)
78                )
79            }
80            |
81            sp!(tuple!(face_pair, face_pair, face_pair)) => {|(a,b,c)| ObjLine::Face(a,b,c)}
82            |
83            sp!(tuple!(face_triple, face_triple, face_triple)) =>  {|(a,b,c)| ObjLine::Face(a,b,c)}
84        ),
85        end_of_line
86    )
87);
88
89named!(
90    comment_line<ObjLine>,
91    map!(sp!(comment), |s| ObjLine::Comment(
92        str::from_utf8(s).unwrap().trim().to_string()
93    ))
94);
95
96named!(
97    parse_obj_line<ObjLine>,
98    alt!(
99        vertex_line
100            | normal_line
101            | vertex_param_line
102            | texcoord_line
103            | face_line
104            | object_line
105            | group_line
106            | mtllib_line
107            | usemtl_line
108            | s_line
109            | comment_line
110    )
111);
112
113pub struct ObjParser<R> {
114    reader: R,
115}
116
117impl<R> ObjParser<R>
118where
119    R: BufRead,
120{
121    pub fn new(reader: R) -> Self {
122        ObjParser { reader }
123    }
124}
125
126impl<R> Iterator for ObjParser<R>
127where
128    R: BufRead,
129{
130    type Item = ObjLine;
131
132    fn next(&mut self) -> Option<Self::Item> {
133        use nom::IResult;
134        let mut line = String::new();
135        let read_result = self.reader.read_line(&mut line);
136        match read_result {
137            Ok(len) => {
138                if len > 0 {
139                    let result = parse_obj_line(line.as_bytes());
140                    match result {
141                        IResult::Done(_, o) => Some(o),
142                        IResult::Error(_e) => None,
143                        IResult::Incomplete(_) => self.next(),
144                    }
145                } else {
146                    None
147                }
148            }
149            Err(_o) => None,
150        }
151    }
152}
153
154#[cfg(test)]
155mod tests {
156
157    use super::*;
158    use std::fs::File;
159    use std::io::BufReader;
160
161    #[test]
162    fn parser_can_read_from_file() -> Result<(), Box<dyn std::error::Error>> {
163        let file = File::open("assets/cube.obj")?;
164        let parser = ObjParser::new(BufReader::new(file));
165        let parsed_lines = parser.collect::<Vec<_>>();
166        assert_eq!(parsed_lines.len(), 51);
167        Ok(())
168    }
169
170    #[test]
171    fn can_parse_any_line() {
172        let result =
173            parse_obj_line("f 1/11/4 1/3/4 1/11/4  #this is an important face \n".as_bytes());
174        let (_, line) = result.unwrap();
175        assert_eq!(
176            line,
177            ObjLine::Face(
178                FaceIndex(1, Some(11), Some(4)),
179                FaceIndex(1, Some(3), Some(4)),
180                FaceIndex(1, Some(11), Some(4))
181            )
182        );
183    }
184
185    #[test]
186    fn can_ignore_comment_at_eol() {
187        let ff = face_line("f 1/11/4 1/3/4 1/11/4  #this is an important face \n".as_bytes());
188        let (_, b) = ff.unwrap();
189        assert_eq!(
190            b,
191            ObjLine::Face(
192                FaceIndex(1, Some(11), Some(4)),
193                FaceIndex(1, Some(3), Some(4)),
194                FaceIndex(1, Some(11), Some(4))
195            )
196        );
197    }
198
199    #[test]
200    fn can_parse_face_triple() {
201        named!(sp_face<FaceIndex>, sp!(face_triple));
202        let ff = face_triple("1/11/4".as_bytes());
203        let (_, b) = ff.unwrap();
204        assert_eq!(b, FaceIndex(1, Some(11), Some(4)));
205    }
206
207    #[test]
208    fn can_parse_face_line_1() {
209        let ff = face_line("f 1/11/4 1/3/4 1/11/4  \n".as_bytes());
210        let (_, b) = ff.unwrap();
211        assert_eq!(
212            b,
213            ObjLine::Face(
214                FaceIndex(1, Some(11), Some(4)),
215                FaceIndex(1, Some(3), Some(4)),
216                FaceIndex(1, Some(11), Some(4))
217            )
218        );
219    }
220
221    #[test]
222    fn can_parse_face_line_2() {
223        //
224        let ff = face_line("f 1/3 2/62 4/3\n".as_bytes());
225        let (_, b) = ff.unwrap();
226        assert_eq!(
227            b,
228            ObjLine::Face(
229                FaceIndex(1, Some(3), None),
230                FaceIndex(2, Some(62), None),
231                FaceIndex(4, Some(3), None),
232            )
233        );
234    }
235
236    #[test]
237    fn can_parse_face_line_3() {
238        let ff = face_line("f 1//4 1//4 1//11  \n".as_bytes());
239        let (_, b) = ff.unwrap();
240        assert_eq!(
241            b,
242            ObjLine::Face(
243                FaceIndex(1, None, Some(4)),
244                FaceIndex(1, None, Some(4)),
245                FaceIndex(1, None, Some(11))
246            )
247        );
248    }
249
250    #[test]
251    fn can_parse_face_line_4() {
252        let ff = face_line("f 42 1 11  \n".as_bytes());
253        let (_, b) = ff.unwrap();
254        assert_eq!(
255            b,
256            ObjLine::Face(
257                FaceIndex(42, None, None),
258                FaceIndex(1, None, None),
259                FaceIndex(11, None, None)
260            )
261        );
262    }
263
264    #[test]
265    fn can_parse_face_line_5() {
266        let ff = face_line("f 42/ 1/ 11/  \n".as_bytes());
267        let (_, b) = ff.unwrap();
268        assert_eq!(
269            b,
270            ObjLine::Face(
271                FaceIndex(42, None, None),
272                FaceIndex(1, None, None),
273                FaceIndex(11, None, None)
274            )
275        );
276    }
277
278    #[test]
279    fn can_parse_face_line_6() {
280        let ff = face_line("f 42// 1// 11// \t \n".as_bytes());
281        let (_, b) = ff.unwrap();
282        assert_eq!(
283            b,
284            ObjLine::Face(
285                FaceIndex(42, None, None),
286                FaceIndex(1, None, None),
287                FaceIndex(11, None, None)
288            )
289        );
290    }
291
292    #[test]
293    fn can_parse_texcoord_line() {
294        let vline = "vt -1.000000 -1.000000 \r\n".as_bytes();
295        let v = texcoord_line(vline);
296        let (_a, b) = v.unwrap();
297        assert_eq!(b, ObjLine::TextureUVW(-1.0, -1.0, None));
298    }
299
300    #[test]
301    fn can_parse_normal_line() {
302        let vline = "vn -1.000000 -1.000000 1.000000  \r\n".as_bytes();
303        let v = normal_line(vline);
304        let (_, b) = v.unwrap();
305        assert_eq!(b, ObjLine::Normal(-1.0, -1.0, 1.0));
306    }
307
308    #[test]
309    #[should_panic]
310    fn invalid_vertex_line_fails() {
311        let vline = "vZZ -1.000000 -1.000000 1.000000 \r\n".as_bytes();
312        let v = vertex_line(vline);
313        let (_, b) = v.unwrap();
314        assert_eq!(b, ObjLine::Vertex(-1.0, -1.0, 1.0, None));
315    }
316
317    #[test]
318    fn can_parse_vertex_parameter_line() {
319        let vline = "vp -1.000000 -1.000000 1.000000 \r\n".as_bytes();
320        let v = vertex_param_line(vline);
321        let (_, b) = v.unwrap();
322        assert_eq!(b, ObjLine::VertexParam(-1.0, -1.0, 1.0));
323    }
324
325    #[test]
326    fn can_parse_vertex_line_with_optional_w_value() {
327        let vline = "v -1.000000 -1.000000 1.000000 42.000\r\n".as_bytes();
328        let v = vertex_line(vline);
329        let (_, b) = v.unwrap();
330        assert_eq!(b, ObjLine::Vertex(-1.0, -1.0, 1.0, Some(42.0)));
331    }
332
333    #[test]
334    fn can_parse_vertex_line() {
335        let vline = "v -1.000000 -1.000000 1.000000 \r\n".as_bytes();
336        let v = vertex_line(vline);
337        let (_, b) = v.unwrap();
338        assert_eq!(b, ObjLine::Vertex(-1.0, -1.0, 1.0, None));
339    }
340
341    #[test]
342    fn can_parse_object_line() {
343        let cmt = object_line("o someobject.999asdf.7 \n".as_bytes());
344        let (_, b) = cmt.unwrap();
345        assert_eq!(b, ObjLine::ObjectName("someobject.999asdf.7".to_string()));
346    }
347
348    #[test]
349    fn can_parse_mtllib_line() {
350        let cmt = mtllib_line("mtllib somelib \n".as_bytes());
351        let (_, b) = cmt.unwrap();
352        assert_eq!(b, ObjLine::MtlLib("somelib".to_string()));
353    }
354
355    #[test]
356    fn can_parse_usemtl_line() {
357        let cmt = usemtl_line("usemtl SomeMaterial\n".as_bytes());
358        let (_, b) = cmt.unwrap();
359        assert_eq!(b, ObjLine::UseMtl("SomeMaterial".to_string()));
360    }
361
362    #[test]
363    fn can_parse_s_line() {
364        let cmt = s_line("s off\n".as_bytes());
365        let (_, b) = cmt.unwrap();
366        assert_eq!(b, ObjLine::SmoothShading("off".to_string()));
367    }
368
369    const CUBE_MODEL: &'static str = "
370# Blender v3.78 (sub 0) OBJ File: 'untitled.blend'
371# www.blender.org
372mtllib cube.mtl
373o Cube_Cube.001
374v -1.000000 -1.000000 1.000000
375v -1.000000 1.000000 1.000000
376v -1.000000 -1.000000 -1.000000
377v -1.000000 1.000000 -1.000000
378v 1.000000 -1.000000 1.000000
379v 1.000000 1.000000 1.000000
380v 1.000000 -1.000000 -1.000000
381v 1.000000 1.000000 -1.000000
382vt 0.0000 0.0000
383vt 1.0000 0.0000
384vt 1.0000 1.0000
385vt 0.0000 0.0000
386vt 1.0000 0.0000
387vt 1.0000 1.0000
388vt 0.0000 0.0000
389vt 1.0000 0.0000
390vt 1.0000 1.0000
391vt 0.0000 0.0000
392vt 1.0000 0.0000
393vt 1.0000 1.0000
394vt 0.0000 0.0000
395vt 1.0000 0.0000
396vt 1.0000 1.0000
397vt 1.0000 0.0000
398vt 1.0000 0.0000
399vt 1.0000 0.0000
400vt 1.0000 1.0000
401vn -1.0000 0.0000 0.0000
402vn 0.0000 0.0000 -1.0000
403vn 1.0000 0.0000 0.0000
404vn 0.0000 0.0000 1.0000
405vn 0.0000 -1.0000 0.0000
406vn 0.0000 1.0000 0.0000
407usemtl None
408s off
409f 2/1/1 3/2/1 1/3/1
410f 4/4/2 7/5/2 3/6/2
411f 8/7/3 5/8/3 7/9/3
412f 6/10/4 1/11/4 5/12/4
413f 7/13/5 1/11/5 3/6/5
414f 4/4/6 6/14/6 8/15/6
415f 2/1/1 4/16/1 3/6/1
416f 4/4/2 8/17/2 7/9/2
417f 8/7/3 6/14/3 5/12/3
418f 6/10/4 2/18/4 1/3/4
419f 7/13/5 5/8/5 1/3/5
420f 4/4/6 2/18/6 6/19/6
421";
422}