e2rcore/implement/file/
wavefrontobj.rs

1#![allow(non_snake_case)]
2#![allow(unused_variables)]
3
4extern crate pretty_env_logger;
5extern crate nom;
6
7use std::str;
8use std::str::FromStr;
9
10use self::nom::digit;
11
12use interface::i_wavefront::obj::*;
13use interface::i_file::IParseStr;
14
15// named!(end_of_line, alt!(
16//     nom::eof!()
17//         |
18//     nom::eol
19//         |
20//     comment  // handle end of line comments - these are not kept
21// ));
22
23// named!(comment, delimited!(
24//     tag!("#"),
25//     take_until!("\n"),
26//     alt!( eof!() | nom::eol )
27// ));
28
29named!( single_word< &str, &str >,
30        take_until_either!(" \n\r\t")
31);
32
33//todo: add "_" to the set of allowable characters
34named!( any_nonwhitespace< &str, &str >,
35        do_parse!(
36            word: ws!(nom::alphanumeric) >>
37            (
38                word
39            )
40        )
41);
42
43named!( parse_mtllib< &str, String >,
44        do_parse!(
45            ws!( tag!("mtllib") ) >>
46            path: single_word >>
47            ( path.to_string() )
48        )
49);
50
51named!( parse_material< &str, String >,
52        do_parse!(
53            ws!( tag!("usemtl") ) >>
54            mtl: single_word >>
55            ( mtl.to_string() )
56        )
57);
58
59named!( parse_g< &str, String >,
60        do_parse!(
61            ws!( tag!("g") ) >>
62            path: single_word >>
63            ( path.to_string() )
64        )
65);
66
67named!( parse_s< &str, String >,
68        do_parse!(
69            ws!( tag!("s") ) >>
70            path: single_word >>
71            ( path.to_string() )
72        )
73);
74
75named!( peek_s< &str, &str >,
76        peek!(
77            ws!( tag!("s") )
78        )
79);
80
81named!( v< &str, [ f32; 3] >,
82        do_parse!(
83            ws!(tag!("v")) >>
84            pos0: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
85            pos1: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
86            pos2: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
87            ( [ pos0, pos1, pos2 ] )
88        )
89);
90
91named!( vn< &str, [ f32; 3] >,
92        do_parse!(
93            ws!( tag!("vn") ) >>
94            n0: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
95            n1: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
96            n2: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
97            ( [ n0, n1, n2 ] )
98        )
99);
100
101named!( vt< &str, [ f32; 2] >,
102        do_parse!(
103            ws!( tag!("vt") ) >>
104            vt0: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
105            vt1: alt!( ws!(nom::float_s) | map_res!(ws!(digit),FromStr::from_str)) >>
106            ( [ vt0, vt1 ] )
107        )
108);
109
110
111named!( f_vtn< &str, Face >,
112        do_parse!(
113            ws!( tag!("f") ) >>
114            v0: map_res!(ws!(digit), FromStr::from_str) >>
115            tag!("/") >>
116            tc0: map_res!(ws!(digit), FromStr::from_str) >>
117            tag!("/") >>
118            n0: map_res!(ws!(digit), FromStr::from_str) >>
119
120            v1: map_res!(ws!(digit), FromStr::from_str) >>
121            tag!("/") >>
122            tc1: map_res!(ws!(digit), FromStr::from_str) >>
123            tag!("/") >>
124            n1: map_res!(ws!(digit), FromStr::from_str) >>
125
126            v2: map_res!(ws!(digit), FromStr::from_str) >>
127            tag!("/") >>
128            tc2: map_res!(ws!(digit), FromStr::from_str) >>
129            tag!("/") >>
130            n2: map_res!(ws!(digit), FromStr::from_str) >>
131                
132            (
133                Face {
134                    _vert_index: [ v0, v1, v2 ],
135                    _tc_index: Some( [ tc0, tc1, tc2 ] ),
136                    _normal_index: Some( [ n0, n1, n2 ] ),
137                }
138            )
139        )
140);
141
142named!( f_vt< &str, Face >,
143        do_parse!(
144            ws!( tag!("f") ) >>
145            v0: map_res!(ws!(digit), FromStr::from_str) >>
146            tag!("/") >>
147            tc0: map_res!(ws!(digit), FromStr::from_str) >>
148
149            v1: map_res!(ws!(digit), FromStr::from_str) >>
150            tag!("/") >>
151            tc1: map_res!(ws!(digit), FromStr::from_str) >>
152
153            v2: map_res!(ws!(digit), FromStr::from_str) >>
154            tag!("/") >>
155            tc2: map_res!(ws!(digit), FromStr::from_str) >>
156                
157            (
158                Face {
159                    _vert_index: [ v0, v1, v2 ],
160                    _tc_index: Some( [ tc0, tc1, tc2 ] ),
161                    _normal_index: None,
162                }
163            )
164        )
165);
166
167named!( f_vn< &str, Face >,
168        do_parse!(
169            ws!( tag!("f") ) >>
170            v0: map_res!(ws!(digit), FromStr::from_str) >>
171            ws!(tag!("/")) >>
172            ws!(tag!("/")) >>
173            n0: map_res!(ws!(digit), FromStr::from_str) >>
174
175            v1: map_res!(ws!(digit), FromStr::from_str) >>
176            ws!(tag!("/")) >>
177            ws!(tag!("/")) >>
178            n1: map_res!(ws!(digit), FromStr::from_str) >>
179
180            v2: map_res!(ws!(digit), FromStr::from_str) >>
181            ws!(tag!("/")) >>
182            ws!(tag!("/")) >>
183            n2: map_res!(ws!(digit), FromStr::from_str) >>
184                
185            (
186                Face {
187                    _vert_index: [ v0, v1, v2 ],
188                    _tc_index: None,
189                    _normal_index: Some( [ n0, n1, n2 ] ),
190                }
191            )
192        )
193);
194
195named!( f_v< &str, Face >,
196        do_parse!(
197            ws!( tag!("f") ) >>
198            v0: map_res!(ws!(digit), FromStr::from_str) >>
199
200            v1: map_res!(ws!(digit), FromStr::from_str) >>
201
202            v2: map_res!(ws!(digit), FromStr::from_str) >>
203                
204            (
205                Face {
206                    _vert_index: [ v0, v1, v2 ],
207                    _tc_index: None,
208                    _normal_index: None,
209                }
210            )
211        )
212);
213
214named!( f< &str, Face >,
215        do_parse!(
216            f: alt!( f_vtn | f_vt | f_vn |f_v ) >>
217            ( f )
218        )
219);
220
221named!( peek_comments< &str, &str >,
222        peek!(
223            ws!( tag!("#") )
224        )
225);
226
227named!( consume_comments_start< &str, () >,
228        do_parse!(
229            ws!(tag!("#")) >>
230            take_until_either!( "\n\r" ) >>
231            ()
232        )
233);
234
235named!( consume_comments< &str, &str >,
236        take_until_either!( "\n\r" )
237);
238
239named!( consume_newline< &str, &str >,
240        not!( take_until_and_consume!( "\n\r" ) )
241);
242
243named!( peek_g< &str, &str >,
244        peek!(
245            ws!( tag!("g") )
246        )
247);
248
249named!( peek_vertex< &str, &str >,
250        peek!(
251            ws!( tag!("v ") )
252        )
253);
254
255named!( peek_texture_coord< &str, &str >,
256        peek!(
257            ws!( tag!("vt") )
258        )
259);
260
261named!( peek_vertex_normal< &str, &str >,
262        peek!(
263            ws!( tag!("vn") )
264        )
265);
266
267named!( peek_face< &str, &str >,
268        peek!(
269            ws!( tag!("f") )
270        )
271);
272
273named!( peek_material< &str, &str >,
274        peek!(
275            ws!( tag!("usemtl") )
276        )
277);
278
279named!( peek_mtllib< &str, &str >,
280        peek!(
281            ws!( tag!("mtllib") )
282        )
283);
284
285fn peek_and_consume_comments( mut input: & str ) -> Option< & str > {
286    match peek_comments( input ) {
287        nom::IResult::Done( i, o ) => {
288            match consume_comments_start( i ) {
289                nom::IResult::Done( j, o ) => {
290                    input = j;
291                },
292                _ => {},
293            }
294            match consume_comments( input ) {
295                nom::IResult::Done( j, o ) => {
296                    input = j;
297                },
298                _ => {},
299            }
300            match consume_newline( input ) {
301                nom::IResult::Done( k, o ) => {
302                    input = k;
303                },
304                _ => {},
305            }
306            return Some( input )
307        },
308        _ => {},
309    }
310    None
311}
312
313fn parse_group( mut buf: & str ) -> Result< ( & str, Option<Group> ), & 'static str > {
314
315    let mut group = None;
316    let mut material = None;
317    let mut vertices = vec![];
318    let mut tx_coords = vec![];
319    let mut normals = vec![];
320    let mut faces = vec![];
321    
322    loop {
323        // println!("Loop inner: {:?}", &buf[..20] );
324        let mut progress = false;
325
326        match peek_and_consume_comments( buf ) {
327            Some(x) => {
328                buf = x;
329                continue;
330            },
331            _ => {}
332        }
333
334        match peek_s( buf ) {
335            nom::IResult::Done( i, o ) => {
336                match parse_s( buf ) {
337                    nom::IResult::Done( i, o ) => {
338                        buf = i;
339                        progress = true;
340                    },
341                    _ => {},
342                }
343            },
344            _ => {},
345        }
346        
347        match peek_g( buf ) {
348            nom::IResult::Done( i, o ) => {
349                if let Some(_) = group {
350                    break;
351                }
352                match parse_g( buf ) {
353                    nom::IResult::Done( i, o ) => {
354                        buf = i;
355                        group = Some(o);
356                        progress = true;
357                    },
358                    _ => {},
359                }
360            },
361            _ => {},
362        }
363
364        match peek_vertex( buf ) {
365            nom::IResult::Done( i, o ) => {
366                match v( buf ) {
367                    nom::IResult::Done( i, o ) => {
368                        buf = i;
369                        vertices.push( o );
370                        progress = true;
371                    },
372                    _ => {
373                        return Err("parse vertex coord")
374                    },
375                }
376            },
377            _ => {},
378        }
379
380        match peek_texture_coord( buf ) {
381            nom::IResult::Done( i, o ) => {
382                match vt( buf ) {
383                    nom::IResult::Done( i, o ) => {
384                        buf = i;
385                        tx_coords.push( o );
386                        progress = true;
387                    },
388                    _ => {
389                        return Err("parse texture coord unsuccessful")
390                    },
391                }
392            },
393            _ => {},
394        }
395
396        match peek_vertex_normal( buf ) {
397            nom::IResult::Done( i, o ) => {
398                match vn( buf ) {
399                    nom::IResult::Done( i, o ) => {
400                        buf = i;
401                        normals.push( o );
402                        progress = true;
403                    },
404                    _ => {
405                        return Err("parse vertex normal unsuccessful")
406                    },
407                }
408            },
409            _ => {},
410        }
411
412        match peek_face( buf ) {
413            nom::IResult::Done( i, o ) => {
414                match f( buf ) {
415                    nom::IResult::Done( i, o ) => {
416                        buf = i;
417                        faces.push( o );
418                        progress = true;
419                    },
420                    _ => {
421                        return Err("parse face unsuccessful")
422                    },
423                }
424            },
425            _ => {},
426        }
427
428        match peek_material( buf ) {
429            nom::IResult::Done( i, o ) => {
430                match parse_material( buf ) {
431                    nom::IResult::Done( i, o ) => {
432                        buf = i;
433                        material = Some( o );
434                        progress = true;
435                    },
436                    _ => {
437                        // return Err("parse material unsuccessful")
438                    },
439                }
440            },
441            _ => {},
442        }
443            
444        if !progress {
445            break;
446        }
447    }
448
449    // if let None = group {
450    //     return Err( "group name missing" )
451    // }
452    // if let None = material {
453    //     return Err( "material name missing" )
454    // }
455
456    if vertices.len() == 0 {
457        return Ok( ( buf, None ) )
458    }
459
460    Ok(
461        ( buf,
462          Some( Group {
463              _name: None,
464              _group: group,
465              _material: material,
466              _verts: vertices,
467              _vert_normals: normals,
468              _faces: faces,
469              _texture_coords: tx_coords,
470          } )
471        )
472    )
473}
474
475pub fn parse( input: & str ) -> Result< Collection, & 'static str > {
476    
477    let mut buf = input;
478
479    let mut groups = vec![];
480
481    let mut mtllib = None;
482
483    loop {
484        match peek_and_consume_comments( buf ) {
485            Some(x) => {
486                buf = x;
487                continue;
488            },
489            _ => {}
490        }
491        break;
492    }
493
494    match peek_mtllib( buf ) {
495        nom::IResult::Done( i, o ) => {
496            match parse_mtllib( buf ) {
497                nom::IResult::Done( i, o ) => {
498                    buf = i;
499                    mtllib = Some( o );
500                },
501                _ => {
502                    return Err("parse mtllib unsuccessful")
503                },
504            }
505        },
506        _ => {},
507    }
508
509    loop {
510        
511        // println!("Loop");
512        let mut progress = false;
513        match parse_group( buf ) {
514            Ok( ( i, g ) ) => {
515                match g {
516                    Some(o) => {
517                        // println!( "{:?}", o );
518                        groups.push( o );
519                        buf = i;
520                        progress = true;
521                    },
522                    _ => {
523                        break;
524                    }
525                }
526            },
527            Err( e ) => {
528                return Err( e )
529            },
530        }
531        if !progress {
532            break;
533        }
534    }
535
536    if let None = mtllib {
537        return Err( "mtllib missing" )
538    }
539
540    Ok(
541        Collection {
542            _mtllib: mtllib.unwrap(),
543            _groups: groups,
544        }
545    )
546}