diff --git a/src/main.rs b/src/main.rs index 77a7240..8602e60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,27 +15,143 @@ use std::io::Read; use std::path::Path; use std::time::Duration; -pub struct Iqm { - version: u32, - filesize: u32, - flags: u32, +mod iqm_consts { + pub const VERSION: usize = 0; + pub const FILESIZE: usize = 1; + pub const FLAGS: usize = 2; + pub const NUM_TEXT: usize = 3; + pub const OFS_TEXT: usize = 4; + pub const NUM_MESHES: usize = 5; + pub const OFS_MESHES: usize = 6; + pub const NUM_VERTEXARRAYS: usize = 7; + pub const NUM_VERTEXES: usize = 8; + pub const OFS_VERTEXARRAYS: usize = 9; + pub const NUM_TRIANGLES: usize = 10; + pub const OFS_TRIANGLES: usize = 11; + pub const OFS_ADJACENCY: usize = 12; + pub const NUM_JOINTS: usize = 13; + pub const OFS_JOINTS: usize = 14; + pub const NUM_POSES: usize = 15; + pub const OFS_POSES: usize = 16; + pub const NUM_ANIMS: usize = 17; + pub const OFS_ANIMS: usize = 18; + pub const NUM_FRAMES: usize = 19; + pub const NUM_FRAMECHANNELS: usize = 20; + pub const OFS_FRAMES: usize = 21; + pub const OFS_BOUNDS: usize = 22; + pub const NUM_COMMENT: usize = 23; + pub const OFS_COMMENT: usize = 24; + pub const NUM_EXTENSIONS: usize = 25; + pub const OFS_EXTENSIONS: usize = 26; } -pub fn parse_iqm (input: &[u8]) -> IResult<&[u8], Iqm> { - let (input, _) = tag (b"INTERQUAKEMODEL\0")(input)?; - let (input, version) = le_u32 (input)?; - - // I only know how to parse version 2 - assert_eq! (version, 2); - - let (input, filesize) = le_u32 (input)?; - let (input, flags) = le_u32 (input)?; - - Ok ((input, Iqm { - version, - filesize, - flags, - })) +#[derive (Debug)] +pub struct IqmMesh { + name: u32, + material: u32, + first_vertex: u32, + num_vertexes: u32, + first_triangle: u32, + num_triangles: u32, +} + +#[derive (Debug)] +pub struct IqmHeader { + fields: [u32; 27], +} + +#[derive (Debug)] +pub struct IqmModel { + header: IqmHeader, + text: Vec , + meshes: Vec , +} + +impl IqmHeader { + pub fn from_slice (input: &[u8]) -> IResult <&[u8], IqmHeader> { + let (input, _) = tag (b"INTERQUAKEMODEL\0")(input)?; + let (input, version) = le_u32 (input)?; + + // I only know how to parse version 2 + assert_eq! (version, 2); + + let mut input = input; + let mut fields = [0; 27]; + fields [0] = version; + + for index in 1..fields.len () { + let (i, h) = le_u32 (input)?; + input = i; + fields [usize::from (index)] = h; + } + + Ok ((input, IqmHeader { + fields, + })) + } +} + +impl IqmMesh { + pub fn from_slice (input: &[u8]) -> IResult <&[u8], IqmMesh> { + let mut result = IqmMesh { + name: 0, + material: 0, + first_vertex: 0, + num_vertexes: 0, + first_triangle: 0, + num_triangles: 0, + }; + + let mut input = input; + for field in [ + &mut result.name, + &mut result.material, + &mut result.first_vertex, + &mut result.num_vertexes, + &mut result.first_triangle, + &mut result.num_triangles, + ].iter_mut () { + let (i, f) = le_u32 (input)?; + input = i; + **field = f; + } + + Ok ((input, result)) + } +} + +impl IqmModel { + pub fn from_slice (input: &[u8]) -> IqmModel { + let header = IqmHeader::from_slice (input).unwrap ().1; + + let text = { + let offset: usize = header.fields [iqm_consts::OFS_TEXT].try_into ().unwrap (); + let num: usize = header.fields [iqm_consts::NUM_TEXT].try_into ().unwrap (); + Vec::from (&input [offset..offset + num]) + }; + + let meshes = { + let mut meshes = vec! []; + let mesh_size = 6 * 4; + let meshes_offset: usize = header.fields [iqm_consts::OFS_MESHES].try_into ().unwrap (); + + for i in 0..header.fields [iqm_consts::NUM_MESHES] { + let i: usize = i.try_into ().unwrap (); + + let offset = meshes_offset + i * mesh_size; + let mesh_slice = &input [offset..offset + mesh_size]; + + meshes.push (IqmMesh::from_slice (mesh_slice).unwrap ().1); + } + meshes + }; + + IqmModel { + header, + text, + meshes, + } + } } pub fn load_small_file

(name: P) -> Vec @@ -364,9 +480,19 @@ mod tests { #[test] pub fn iqm () { let data = load_small_file ("pumpking.iqm"); - let model = parse_iqm (&data [..]).unwrap ().1; - assert_eq! (model.filesize, 90368); - assert_eq! (model.flags, 0); + { + let model = IqmHeader::from_slice (&data [..]).unwrap ().1; + + assert_eq! (model.fields [1], 90368); + assert_eq! (model.fields [2], 0); + assert_eq! (model.fields [iqm_consts::VERSION], 2); + } + + { + let model = IqmModel::from_slice (&data [..]); + + println! ("{:?}", model.meshes); + } } }