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
15named!( single_word< &str, &str >,
30 take_until_either!(" \n\r\t")
31);
32
33named!( 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 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 },
439 }
440 },
441 _ => {},
442 }
443
444 if !progress {
445 break;
446 }
447 }
448
449 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 let mut progress = false;
513 match parse_group( buf ) {
514 Ok( ( i, g ) ) => {
515 match g {
516 Some(o) => {
517 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}