use std::convert::TryFrom; use std::mem::size_of; use byteorder::{ByteOrder, LittleEndian}; #[derive (Debug)] pub struct Model <'data> { pub data: &'data [u8], } pub struct VertexArray <'model: 'data, 'data> { pub model: &'model Model <'data>, ofs: usize, } pub struct Mesh <'data> { pub model: &'data Model <'data>, ofs: usize, } pub struct HeaderFields <'data> { model: &'data Model <'data>, idx: usize, } pub struct VertexArrays <'data> { model: &'data Model <'data>, idx: usize, } pub struct Meshes <'data> { model: &'data Model <'data>, idx: usize, } #[derive (Debug)] pub enum Error { BadMagic, UnsupportedVersion, HeaderTooShort, ParseMeshFailed, ParseVertexArrayFailed, } use crate::names; use names::consts; use names::MAGIC; pub const HEADER_FIELD_COUNT: usize = 27; // If you are using IQM models on an 8-bit or 16-bit microcontroller // you're smarter than me anyway pub fn usize_from (x: u32) -> usize { usize::try_from (x).unwrap () } impl <'data> Iterator for HeaderFields <'data> { type Item = u32; fn next (&mut self) -> Option { if self.idx >= HEADER_FIELD_COUNT { return None; } let result = self.model.header_field (self.idx); self.idx += 1; Some (result) } fn size_hint (&self) -> (usize, Option ) { let x = HEADER_FIELD_COUNT - self.idx; (x, Some (x)) } } impl <'data> Iterator for VertexArrays <'data> { type Item = VertexArray <'data, 'data>; fn next (&mut self) -> Option { if self.idx >= usize_from (self.model.header_field (crate::names::consts::NUM_VERTEXARRAYS)) { return None; } let result = self.model.vertexarray (self.idx); self.idx += 1; Some (result) } fn size_hint (&self) -> (usize, Option ) { let x = usize_from (self.model.header_field (crate::names::consts::NUM_VERTEXARRAYS)) - self.idx; (x, Some (x)) } } impl <'data> Iterator for Meshes <'data> { type Item = Mesh <'data>; fn next (&mut self) -> Option { if self.idx >= usize_from (self.model.header_field (crate::names::consts::NUM_MESHES)) { return None; } let result = self.model.mesh (self.idx); self.idx += 1; Some (result) } fn size_hint (&self) -> (usize, Option ) { let x = usize_from (self.model.header_field (crate::names::consts::NUM_MESHES)) - self.idx; (x, Some (x)) } } impl <'data> Model <'data> { pub fn get_root (data: &[u8]) -> Result { if &data [0..MAGIC.len ()] != MAGIC { return Err (Error::BadMagic); } if data.len () < MAGIC.len () + size_of:: () * HEADER_FIELD_COUNT { return Err (Error::HeaderTooShort); } let m = Model { data, }; if m.header_field (consts::VERSION) != 2 { return Err (Error::UnsupportedVersion); } Ok (m) } pub fn header_field (&self, idx: usize) -> u32 { LittleEndian::read_u32 (&self.data [MAGIC.len () + idx * size_of:: ()..]) } pub fn vertexarray (&self, idx: usize) -> VertexArray { use crate::names::consts::*; assert! (idx < usize_from (self.header_field (NUM_VERTEXARRAYS))); let vertexarray_stride = VA_FIELD_COUNT * size_of:: (); VertexArray { model: self, ofs: usize_from (self.header_field (OFS_VERTEXARRAYS)) + idx * vertexarray_stride, } } pub fn mesh (&self, idx: usize) -> Mesh { use crate::names::consts::*; assert! (idx < usize_from (self.header_field (NUM_MESHES))); let mesh_stride = MESH_FIELD_COUNT * size_of:: (); Mesh { model: self, ofs: usize_from (self.header_field (OFS_MESHES)) + idx * mesh_stride, } } pub fn header_fields (&self) -> HeaderFields { HeaderFields { model: self, idx: 0, } } pub fn vertexarrays (&self) -> VertexArrays { VertexArrays { model: self, idx: 0, } } pub fn meshes (&self) -> Meshes { Meshes { model: self, idx: 0, } } } impl <'model: 'data, 'data> VertexArray <'model, 'data> { pub fn field (&self, idx: usize) -> u32 { LittleEndian::read_u32 (&self.model.data [self.ofs + idx * size_of::()..]) } pub fn get_vertex_slice (&self) -> &'data [u8] { use names::consts::*; let stride = size_of:: () * usize_from (self.field (VA_SIZE)); let offset = usize_from (self.field (VA_OFFSET)); let num_bytes = stride * usize_from (self.model.header_field (NUM_VERTEXES)); &self.model.data [offset..offset + num_bytes] } } impl <'data> Mesh <'data> { pub fn field (&self, idx: usize) -> u32 { LittleEndian::read_u32 (&self.model.data [self.ofs + idx * size_of::()..]) } }