209 lines
4.5 KiB
Rust
209 lines
4.5 KiB
Rust
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 <Self::Item> {
|
|
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 <usize>) {
|
|
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 <Self::Item> {
|
|
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 <usize>) {
|
|
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 <Self::Item> {
|
|
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 <usize>) {
|
|
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 <Model, Error> {
|
|
if &data [0..MAGIC.len ()] != MAGIC {
|
|
return Err (Error::BadMagic);
|
|
}
|
|
|
|
if data.len () < MAGIC.len () + size_of::<u32> () * 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::<u32> ()..])
|
|
}
|
|
|
|
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::<u32> ();
|
|
|
|
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::<u32> ();
|
|
|
|
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::<u32>()..])
|
|
}
|
|
|
|
pub fn get_vertex_slice (&self) -> &'data [u8] {
|
|
use names::consts::*;
|
|
|
|
let stride = size_of::<f32> () * 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::<u32>()..])
|
|
}
|
|
}
|