e2rcore/implement/file/
md5mesh_nom.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_md5::mesh::*;
13use interface::i_file::IParseStr;
14    
15named!( shader_path< &str, String >,
16        do_parse!(
17            ws!( tag!("shader") ) >>
18            path: delimited!(
19                tag!("\""),
20                take_until!("\""),
21                tag!("\"")
22            ) >>
23            ( path.to_string() )
24        )
25);
26
27//weights
28named!( md5mesh_weight< &str, Md5Weight >,
29        do_parse!(
30            ws!( tag!("weight") ) >> 
31            idx: map_res!( ws!(digit), FromStr::from_str ) >>
32            joint_idx: map_res!( ws!(digit), FromStr::from_str ) >>
33            weight_bias: ws!(nom::float_s) >>
34            ws!(tag!("(")) >>
35            pos0: ws!(nom::float_s) >>
36            pos1: ws!(nom::float_s) >>
37            pos2: ws!(nom::float_s) >>
38            ws!(tag!(")")) >>    
39            (
40                Md5Weight {
41                    _index: idx,
42                    _joint_index: joint_idx,
43                    _weight_bias:  weight_bias,
44                    _pos: [ pos0, pos1, pos2 ],
45                }
46            )
47        )
48);
49
50named!( md5mesh_weights< &str, Vec<Md5Weight> >,
51        do_parse!(
52            ws!( tag!("numweights") ) >>
53            count_weights: map_res!( ws!(digit), FromStr::from_str ) >>
54            weights: count!(
55                md5mesh_weight
56                ,count_weights ) >>
57            ( weights )
58        )
59);
60
61named!( md5mesh_vert< &str, Md5Vert >,
62        do_parse!(
63            ws!( tag!("vert") ) >> 
64            idx: map_res!( ws!(digit), FromStr::from_str ) >>
65            ws!(tag!("(")) >>
66            v0: ws!(nom::float_s) >>
67            v1: ws!(nom::float_s) >>
68            ws!(tag!(")")) >>    
69            v2: map_res!( ws!(digit), FromStr::from_str ) >>
70            v3: map_res!( ws!(digit), FromStr::from_str ) >>
71            (
72                Md5Vert {
73                    _index: idx,
74                    _tex_coords: [ v0, v1 ],
75                    _weight_start: v2,
76                    _weight_count: v3,
77                    _normal: [0f32;3],
78                    _pos: [0f32;3],
79                }
80            )
81        )
82);
83
84named!( md5mesh_verts< &str, Vec<Md5Vert> >,
85        do_parse!(
86            ws!( tag!("numverts") ) >>
87            count_verts: map_res!( ws!(digit), FromStr::from_str ) >>
88            verts: count!(
89                md5mesh_vert
90                ,count_verts ) >>
91            ( verts )
92        )
93);
94
95named!( md5mesh_tri< &str, Md5Tri >,
96        do_parse!(
97            ws!( tag!("tri") ) >> 
98            idx: map_res!( ws!(digit), FromStr::from_str ) >>
99            v0: map_res!( ws!(digit), FromStr::from_str ) >>
100            v1: map_res!( ws!(digit), FromStr::from_str ) >>
101            v2: map_res!( ws!(digit), FromStr::from_str ) >>
102            (
103                Md5Tri {
104                    _index: idx,
105                    _vert_indices: [ v0, v1, v2 ]
106                }
107            )
108        )
109);
110        
111named!( md5mesh_tris< &str, Vec< Md5Tri > >,
112        do_parse!(
113            ws!( tag!("numtris") ) >>
114            count_tris: map_res!( ws!(digit), FromStr::from_str ) >>
115            tris: count!(
116                md5mesh_tri
117                ,count_tris ) >>
118            ( tris )
119        )
120);
121
122named!( md5mesh_parse_opening< &str, () >,
123        do_parse!(
124            ws!( tag!("mesh") ) >>
125            ws!( tag!("{") ) >>
126            ()
127        )
128);
129named!( md5mesh_parse_closing< &str, () >,
130        do_parse!(
131            ws!( tag!("}") ) >>
132            ()
133        )
134);
135
136named!( peek_shader< &str, &str >,
137        peek!(
138            ws!( tag!("shader") )
139        )
140);
141
142named!( peek_verts< &str, &str >,
143        peek!(
144            ws!( tag!("numverts") )
145        )
146);
147
148named!( peek_tris< &str, &str >,
149        peek!(
150            ws!( tag!("numtris") )
151        )
152);
153
154named!( peek_weights< &str, &str >,
155        peek!(
156            ws!( tag!("numweights") )
157        )
158);
159
160named!( peek_version< &str, &str >,
161        peek!(
162            ws!( tag!("MD5Version") )
163        )
164);
165
166named!( md5_version< &str, isize >,
167        do_parse!(
168            ws!( tag!("MD5Version") ) >>
169            version: map_res!( ws!(digit), FromStr::from_str ) >>
170            ( version )
171        )
172);
173
174named!( peek_commandline< &str, &str >,
175        peek!(
176            ws!( tag!("commandline") )
177        )
178);
179
180named!( md5_commandline< &str, String >,
181        do_parse!(
182            ws!( tag!("commandline") ) >>
183            cmd: delimited!(
184                tag!("\""),
185                take_until!("\""),
186                tag!("\"")
187            ) >>
188            ( cmd.to_string() )
189        )
190);
191
192named!( peek_numJoints< &str, &str >,
193        peek!(
194            ws!( tag!("numJoints") )
195        )
196);
197
198named!( md5_numJoints< &str, isize >,
199        do_parse!(
200            ws!( tag!("numJoints") ) >>
201            num: map_res!( ws!(digit), FromStr::from_str ) >>
202            ( num )
203        )
204);
205
206named!( peek_numMeshes< &str, &str >,
207        peek!(
208            ws!( tag!("numMeshes") )
209        )
210);
211
212named!( md5_numMeshes< &str, isize >,
213        do_parse!(
214            ws!( tag!("numMeshes") ) >>
215            num: map_res!( ws!(digit), FromStr::from_str ) >>    
216            ( num )
217        )
218);
219
220named!( peek_joints< &str, &str >,
221        peek!(
222            ws!( tag!("joints") )
223        )
224);
225
226
227named!( signed_num< &str, &str >,
228        recognize!(
229            do_parse!(
230                sgn: alt!( tag!("+") | tag!("-") | tag!("") ) >>
231                d: digit >> ()
232            )
233        )
234);
235
236named!( md5mesh_joint< &str, Md5Joint >,
237        do_parse!(
238            name: ws!(delimited!(
239                tag!("\""),
240                take_until!("\""),
241                tag!("\"")
242            ) ) >>
243            idx: map_res!(ws!(signed_num), <isize as FromStr>::from_str ) >>   
244            ws!(tag!("(")) >>
245            p0: ws!(nom::float_s) >>
246            p1: ws!(nom::float_s) >>
247            p2: ws!(nom::float_s) >>
248            ws!(tag!(")")) >>
249            ws!(tag!("(")) >>
250            o0: ws!(nom::float_s) >>
251            o1: ws!(nom::float_s) >>
252            o2: ws!(nom::float_s) >>
253            ws!(tag!(")")) >>
254            (
255                Md5Joint {
256                    _name: name.to_string(),
257                    _parent_index: idx as i64,
258                    _pos: [ p0, p1, p2 ],
259                    _orient: [ o0, o1, o2 ],
260                    _rot: Default::default(),
261                }
262            )
263        )
264);
265
266named!( md5mesh_joints_opening< &str, &str >,
267        do_parse!(
268            ws!( tag!("joints") ) >>
269            a: ws!( tag!("{") ) >>
270            ( a )    
271        )
272);
273
274named!( md5mesh_joints_closing< &str, () >,
275        do_parse!(
276            ws!( tag!("}") ) >>
277            ()    
278        )
279);
280
281named!( peek_comments< &str, &str >,
282        peek!(
283            ws!( tag!("//") )
284        )
285);
286
287named!( consume_comments_start< &str, () >,
288        do_parse!(
289            take_until_either!( "\n\r" ) >>
290            tag!("//") >>
291            ()
292        )
293);
294
295named!( consume_comments< &str, &str >,
296        take_until_either!( "\n\r" )
297);
298
299named!( consume_newline< &str, &str >,
300        not!( take_until_and_consume!( "\n\r" ) )
301);
302
303fn parse_mesh( input: & str ) -> Result< ( & str, Md5Mesh ), & 'static str > {
304    
305    let mut buf = input;
306    
307    match md5mesh_parse_opening( buf ) {
308        nom::IResult::Done( i, _ ) => {
309            buf = i;
310        },
311        other => {
312            return Err( "no mesh opening token found" )
313        }
314    };
315
316    let mut shader : Option< String > = None;
317    let mut verts : Option< Vec< Md5Vert > > = None;
318    let mut tris : Option< Vec< Md5Tri > > = None;
319    let mut weights : Option< Vec< Md5Weight > > = None;
320
321    loop {
322        
323        let mut progress = false;
324
325        match peek_and_consume_comments( buf ) {
326            Some(x) => {
327                buf = x;
328                progress = true;
329            },
330            _ => {},
331        }
332
333        match peek_shader( buf ) {
334            nom::IResult::Done( _, _ ) => {
335                match shader_path( buf ) {
336                    nom::IResult::Done( i, o ) => {
337                        shader = Some( o );
338                        buf = i;
339                        progress = true;
340                    },
341                    _ => {},
342                }
343            },
344            _ => {},
345        }
346
347        match peek_verts( buf ) {
348            nom::IResult::Done( _, _ ) => {
349                match md5mesh_verts( buf ) {
350                    nom::IResult::Done( i, o ) => {
351                        verts = Some( o );
352                        buf = i;
353                        progress = true;
354                    },
355                    _ => {},
356                }
357            },
358            _ => {},
359        }
360
361        match peek_tris( buf ) {
362            nom::IResult::Done( _, _ ) => {
363                match md5mesh_tris( buf ) {
364                    nom::IResult::Done( i, o ) => {
365                        tris = Some( o );
366                        buf = i;
367                        progress = true;
368                    },
369                    _ => {},
370                }
371            },
372            _ => {},
373        }
374        
375        match peek_weights( buf ) {
376            nom::IResult::Done( _, _ ) => {
377                match md5mesh_weights( buf ) {
378                    nom::IResult::Done( i, o ) => {
379                        weights = Some( o );
380                        buf = i;
381                        progress = true;
382                    },
383                    _ => {},
384                }
385            },
386            _ => {},
387        }
388
389        if !progress {
390            break;
391        }
392    }
393
394    match md5mesh_parse_closing( buf ) {
395        nom::IResult::Done( i, _ ) => {
396            buf = i;
397        },
398        _ => { return Err("mesh closing token not found") },
399    }
400
401    match ( shader, verts, tris, weights ) {
402        ( Some(s), Some(v), Some(t), Some(w) ) => {
403            Ok( ( buf, Md5Mesh {
404                _shader: s,
405                _numverts: v.len() as u64,
406                _numtris: t.len() as u64,
407                _numweights: w.len() as u64,
408                _verts: v,
409                _tris: t,
410                _weights: w,
411            } ) )
412        },
413        _ => {
414            Err( "Mesh parse unsuccessful" )
415        }
416    }
417}
418
419fn peek_and_consume_comments( mut input: & str ) -> Option< & str > {
420    match peek_comments( input ) {
421        nom::IResult::Done( i, o ) => {
422            match consume_comments_start( i ) {
423                nom::IResult::Done( j, o ) => {
424                    input = j;
425                },
426                _ => {},
427            }
428            match consume_comments( input ) {
429                nom::IResult::Done( j, o ) => {
430                    input = j;
431                },
432                _ => {},
433            }
434            match consume_newline( input ) {
435                nom::IResult::Done( k, o ) => {
436                    input = k;
437                },
438                _ => {},
439            }
440            return Some( input )
441        },
442        _ => {},
443    }
444    None
445}
446
447pub struct Md5MeshParser {}
448
449impl IParseStr for Md5MeshParser {
450    type output = Md5MeshRoot;
451
452    fn parse( file_content: &str ) -> Result< Self::output, & 'static str > {
453
454        // let input = file_open( "core/asset/md5/qshambler.md5mesh" ).expect( "input file invalid" );
455
456        let mut buf = file_content;
457
458        let mut version = None;
459        let mut cmdline = None;
460        let mut num_joints = None;
461        let mut num_meshes = None;
462
463        let mut joints : Vec< Md5Joint > = vec![];
464        let mut meshes : Vec< Md5Mesh > = vec![];
465        
466        loop {
467
468            let mut progress = false;
469            
470            match peek_version( buf ) {
471                nom::IResult::Done( _, _ ) => {
472                    match md5_version( buf ) {
473                        nom::IResult::Done( i, o ) => {
474                            version = Some( o );
475                            buf = i;
476                            progress = true;
477                        },
478                        _ => {},
479                    }
480                },
481                _ => {},
482            }
483
484            match peek_commandline( buf ) {
485                nom::IResult::Done( _, _ ) => {
486                    match md5_commandline( buf ) {
487                        nom::IResult::Done( i, o ) => {
488                            cmdline = Some( o );
489                            buf = i;
490                            progress = true;
491                        },
492                        _ => {},
493                    }
494                },
495                _ => {},
496            }
497
498            match peek_numJoints( buf ) {
499                nom::IResult::Done( _, _ ) => {
500                    match md5_numJoints( buf ) {
501                        nom::IResult::Done( i, o ) => {
502                            debug!( "num joints: {:?}", o );
503                            num_joints = Some( o );
504                            buf = i;
505                            progress = true;
506                        },
507                        _ => {},
508                    }
509                },
510                _ => {},
511            }
512
513            match peek_numMeshes( buf ) {
514                nom::IResult::Done( _, _ ) => {
515                    match md5_numMeshes( buf ) {
516                        nom::IResult::Done( i, o ) => {
517                            debug!( "num meshes: {:?}", o );
518                            num_meshes = Some( o );
519                            buf = i;
520                            progress = true;
521                        },
522                        _ => {},
523                    }
524                },
525                _ => {},
526            }
527
528            match peek_joints( buf ) {
529                nom::IResult::Done( _, _ ) => {
530                    match md5mesh_joints_opening( buf ) {
531                        nom::IResult::Done( i, o ) => {
532                            progress = true;
533                            buf = i;
534                        },
535                        _ => {
536                            return Err( "joint opening token not found" )
537                        },
538                    }
539                    match num_joints {
540                        None => {
541                            return Err( "num joints not specified at point of joint parsing" )
542                        },
543                        _ => {},
544                    }
545                    
546                    let n = num_joints.unwrap();
547                    let mut count = 0;
548                    while count < n {
549                        match peek_and_consume_comments( buf ) {
550                            Some(x) => {
551                                progress = true;
552                                buf = x;
553                                continue;
554                            },
555                            _ => {}
556                        }
557                        match md5mesh_joint( buf ) {
558                            nom::IResult::Done( i, o ) => {
559                                buf = i;
560                                progress = true;
561                                joints.push( o );
562                            },
563                            _ => {
564                                return Err("joint parse unsuccessful")
565                            },
566                        }
567
568                        count += 1;
569                    }                
570
571                    match peek_and_consume_comments( buf ) {
572                        Some(x) => {
573                            buf = x;
574                        },
575                        _ => {}
576                    }
577
578                    match md5mesh_joints_closing( buf ) {
579                        nom::IResult::Done( i, o ) => {
580                            progress = true;
581                            buf = i;
582                        },
583                        _ => {},
584                    }
585                },
586                _ => {},
587            }
588
589            if !progress {
590                break;
591            }
592        }
593
594        match peek_and_consume_comments( buf ) {
595            Some(x) => { buf = x; },
596            _ => {},
597        }
598
599        match num_meshes {
600            None => {
601                return Err( "num meshes not present" );
602            },
603            _ => {},
604        }
605
606        for _ in 0..num_meshes.unwrap() {
607            match parse_mesh( buf ) {
608                Ok( ( b, m ) ) => {
609                    buf = b;
610                    meshes.push( m );                
611                },
612                Err(e) => {
613                    return Err(e)
614                }
615            };
616        }
617
618        debug!("num joints: {:?}", joints.len() );
619        debug!("num meshes: {:?}", meshes.len() );
620
621        if let None = version {
622            return Err( "version not present" );
623        }
624        if let None = cmdline {
625            return Err( "cmdline not present" );
626        }
627        match num_joints {
628            Some(x) => {
629                if x != joints.len() as isize {
630                    assert_eq!( x, joints.len() as isize );
631                }
632            }
633            _ => {
634                return Err( "num joints not present" );
635            },
636        }
637
638        assert_eq!( num_meshes.unwrap(), meshes.len() as isize );
639
640        Ok( Md5MeshRoot {
641            _md5ver: version.unwrap() as u64,
642            _cmdline: cmdline.unwrap(),
643            _numjoints: num_joints.unwrap() as u64,
644            _nummeshes: num_meshes.unwrap() as u64,
645            _joints: joints,
646            _meshes: meshes,
647        } )
648    }
649}