use nom::{ IResult, bytes::complete::{tag}, number::complete::{le_u32}, }; use std::convert::TryInto; 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; } mod iqm_types { pub const POSITION: u32 = 0; pub const TEXCOORD: u32 = 1; pub const NORMAL: u32 = 2; pub const TANGENT: u32 = 3; pub const BLENDINDEXES: u32 = 4; pub const BLENDWEIGHTS: u32 = 5; pub const COLOR: u32 = 6; pub const CUSTOM: u32 = 0x10; } mod iqm_formats { pub const BYTE: u32 = 0; pub const UBYTE: u32 = 1; pub const SHORT: u32 = 2; pub const USHORT: u32 = 3; pub const INT: u32 = 4; pub const UINT: u32 = 5; pub const HALF: u32 = 6; pub const FLOAT: u32 = 7; pub const DOUBLE: u32 = 8; } #[derive (Debug)] pub struct IqmMesh { pub name: u32, pub material: u32, pub first_vertex: u32, pub num_vertexes: u32, pub first_triangle: u32, pub num_triangles: u32, } #[derive (Debug)] pub struct IqmHeader { fields: [u32; 27], } #[derive (Debug)] pub struct IqmVertexArray { va_type: u32, va_flags: u32, va_format: u32, va_size: u32, va_offset: u32, } #[derive (Debug)] pub struct IqmModel <'a> { data: &'a [u8], header: IqmHeader, text: Vec , pub meshes: Vec , vertexarrays: 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 IqmVertexArray { pub fn from_slice (input: &[u8]) -> IResult <&[u8], IqmVertexArray> { let mut result = IqmVertexArray { va_type: 0, va_flags: 0, va_format: 0, va_size: 0, va_offset: 0, }; let mut input = input; for field in [ &mut result.va_type, &mut result.va_flags, &mut result.va_format, &mut result.va_size, &mut result.va_offset, ].iter_mut () { let (i, f) = le_u32 (input)?; input = i; **field = f; } Ok ((input, result)) } } impl <'a> IqmModel <'a> { pub fn from_slice (data: &'a [u8]) -> IqmModel <'a> { let header = IqmHeader::from_slice (data).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 (&data [offset..offset + num]) }; let meshes = { let num: usize = header.fields [iqm_consts::NUM_MESHES].try_into ().unwrap (); let mut meshes = Vec::with_capacity (num); let mesh_size = 6 * 4; let meshes_offset: usize = header.fields [iqm_consts::OFS_MESHES].try_into ().unwrap (); for i in 0..num { let offset = meshes_offset + i * mesh_size; let mesh_slice = &data [offset..offset + mesh_size]; meshes.push (IqmMesh::from_slice (mesh_slice).unwrap ().1); } meshes }; //println! ("{:?}", meshes); let vertexarrays = { let num: usize = header.fields [iqm_consts::NUM_VERTEXARRAYS].try_into ().unwrap (); let mut vertexarrays = Vec::with_capacity (num); let vertexarray_size = 5 * 4; let vertexarrays_offset: usize = header.fields [iqm_consts::OFS_VERTEXARRAYS].try_into ().unwrap (); for i in 0..num { let offset = vertexarrays_offset + i * vertexarray_size; let vertexarray_slice = &data [offset..offset + vertexarray_size]; let vertexarray = IqmVertexArray::from_slice (vertexarray_slice).unwrap ().1; //println! ("{:?}", vertexarray); vertexarrays.push (vertexarray); } vertexarrays }; IqmModel { data, header, text, meshes, vertexarrays, } } pub fn get_vertex_slice (&self, vertexarray_index: usize ) -> &[u8] { let vertexarray = &self.vertexarrays [vertexarray_index]; let bytes_per_float = 4; let stride = bytes_per_float * vertexarray.va_size; //assert_eq! (stride, 12); let offset: usize = (vertexarray.va_offset).try_into ().unwrap (); let num_bytes: usize = (stride * self.header.fields [iqm_consts::NUM_VERTEXES]).try_into ().unwrap (); &self.data [offset..offset + num_bytes] } pub fn get_index_slice (&self, mesh_index: usize) -> &[u8] { let mesh = &self.meshes [mesh_index]; let bytes_per_u32 = 4; let indexes_per_tri = 3; let stride = bytes_per_u32 * indexes_per_tri; let offset: usize = (self.header.fields [iqm_consts::OFS_TRIANGLES] + stride * mesh.first_triangle).try_into ().unwrap (); let num_bytes: usize = (stride * mesh.num_triangles).try_into ().unwrap (); &self.data [offset..offset + num_bytes] } }