♻️ Extract zero-copy interface
parent
d68d835baf
commit
86612f4d8e
|
@ -1 +1,2 @@
|
|||
/target
|
||||
/Cargo.lock
|
||||
|
|
100
src/lib.rs
100
src/lib.rs
|
@ -7,65 +7,11 @@ use std::mem::size_of;
|
|||
|
||||
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
|
||||
|
||||
pub mod consts {
|
||||
use iota::iota;
|
||||
iota! {
|
||||
pub const VERSION: usize = iota;
|
||||
, FILESIZE
|
||||
, FLAGS
|
||||
, NUM_TEXT
|
||||
, OFS_TEXT
|
||||
, NUM_MESHES
|
||||
, OFS_MESHES
|
||||
, NUM_VERTEXARRAYS
|
||||
, NUM_VERTEXES
|
||||
, OFS_VERTEXARRAYS
|
||||
, NUM_TRIANGLES
|
||||
, OFS_TRIANGLES
|
||||
, OFS_ADJACENCY
|
||||
, NUM_JOINTS
|
||||
, OFS_JOINTS
|
||||
, NUM_POSES
|
||||
, OFS_POSES
|
||||
, NUM_ANIMS
|
||||
, OFS_ANIMS
|
||||
, NUM_FRAMES
|
||||
, NUM_FRAMECHANNELS
|
||||
, OFS_FRAMES
|
||||
, OFS_BOUNDS
|
||||
, NUM_COMMENT
|
||||
, OFS_COMMENT
|
||||
, NUM_EXTENSIONS
|
||||
, OFS_EXTENSIONS
|
||||
}
|
||||
}
|
||||
pub mod names;
|
||||
pub mod zero_copy;
|
||||
|
||||
pub mod types {
|
||||
iota! {
|
||||
pub const POSITION: usize = iota;
|
||||
, TEXCOORD
|
||||
, NORMAL
|
||||
, TANGENT
|
||||
, BLENDINDEXES
|
||||
, BLENDWEIGHTS
|
||||
, COLOR
|
||||
}
|
||||
pub const CUSTOM: usize = 0x10;
|
||||
}
|
||||
|
||||
pub mod formats {
|
||||
iota! {
|
||||
pub const BYTE: u32 = iota;
|
||||
, UBYTE
|
||||
, SHORT
|
||||
, USHORT
|
||||
, INT
|
||||
, UINT
|
||||
, HALF
|
||||
, FLOAT
|
||||
, DOUBLE
|
||||
}
|
||||
}
|
||||
pub use crate::names::consts;
|
||||
pub use crate::names::types;
|
||||
|
||||
#[derive (Debug, Default)]
|
||||
pub struct Mesh {
|
||||
|
@ -109,13 +55,14 @@ pub enum ModelLoadErr {
|
|||
ParseVertexArrayFailed,
|
||||
}
|
||||
|
||||
use crate::names::MAGIC;
|
||||
|
||||
impl Header {
|
||||
pub fn from_slice (input: &[u8]) -> Result <Header, ModelLoadErr> {
|
||||
let magic = b"INTERQUAKEMODEL\0";
|
||||
if &input [0..magic.len ()] != magic {
|
||||
if &input [0..MAGIC.len ()] != MAGIC {
|
||||
return Err (ModelLoadErr::BadMagic);
|
||||
}
|
||||
let input = &input [magic.len ()..];
|
||||
let input = &input [MAGIC.len ()..];
|
||||
|
||||
let mut header = Header::default ();
|
||||
LittleEndian::read_u32_into (&input [0..header.fields.len () * size_of::<u32> ()], &mut header.fields);
|
||||
|
@ -288,18 +235,14 @@ impl <'a> Model <'a> {
|
|||
|
||||
#[cfg (test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
pub fn nothing () {
|
||||
|
||||
}
|
||||
|
||||
fn load_file <P: AsRef <Path>> (filename: P) -> Vec <u8> {
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
|
||||
let mut f = File::open (filename).unwrap ();
|
||||
let mut data = vec! [0u8; f.metadata ().unwrap ().len ().try_into ().unwrap ()];
|
||||
f.read_exact (&mut data).unwrap ();
|
||||
|
@ -308,6 +251,8 @@ mod test {
|
|||
|
||||
#[test]
|
||||
pub fn load_models () {
|
||||
use super::*;
|
||||
|
||||
let airplane_bytes = load_file ("airplane.iqm");
|
||||
let arrow_bytes = load_file ("arrow.iqm");
|
||||
let truk_bytes = load_file ("truk.iqm");
|
||||
|
@ -316,7 +261,7 @@ mod test {
|
|||
let arrow = Model::from_slice (&arrow_bytes).unwrap ();
|
||||
let truk = Model::from_slice (&truk_bytes).unwrap ();
|
||||
|
||||
use consts::*;
|
||||
use crate::names::consts::*;
|
||||
|
||||
assert_eq! (airplane.header.fields [NUM_VERTEXES], 304);
|
||||
assert_eq! (airplane.header.fields [NUM_TRIANGLES], 156);
|
||||
|
@ -333,4 +278,17 @@ mod test {
|
|||
assert_eq! (truk.meshes.len (), 5);
|
||||
assert_eq! (truk.vertexarrays.len (), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn load_zero_copy () {
|
||||
use crate::zero_copy::*;
|
||||
|
||||
let airplane_bytes = load_file ("airplane.iqm");
|
||||
let arrow_bytes = load_file ("arrow.iqm");
|
||||
let truk_bytes = load_file ("truk.iqm");
|
||||
|
||||
let airplane = Model::get_root (&airplane_bytes);
|
||||
let arrow = Model::get_root (&arrow_bytes);
|
||||
let truk = Model::get_root (&truk_bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
pub const MAGIC: &[u8] = b"INTERQUAKEMODEL\0";
|
||||
|
||||
pub mod consts {
|
||||
use iota::iota;
|
||||
iota! {
|
||||
pub const VERSION: usize = iota;
|
||||
, FILESIZE
|
||||
, FLAGS
|
||||
, NUM_TEXT
|
||||
, OFS_TEXT
|
||||
, NUM_MESHES
|
||||
, OFS_MESHES
|
||||
, NUM_VERTEXARRAYS
|
||||
, NUM_VERTEXES
|
||||
, OFS_VERTEXARRAYS
|
||||
, NUM_TRIANGLES
|
||||
, OFS_TRIANGLES
|
||||
, OFS_ADJACENCY
|
||||
, NUM_JOINTS
|
||||
, OFS_JOINTS
|
||||
, NUM_POSES
|
||||
, OFS_POSES
|
||||
, NUM_ANIMS
|
||||
, OFS_ANIMS
|
||||
, NUM_FRAMES
|
||||
, NUM_FRAMECHANNELS
|
||||
, OFS_FRAMES
|
||||
, OFS_BOUNDS
|
||||
, NUM_COMMENT
|
||||
, OFS_COMMENT
|
||||
, NUM_EXTENSIONS
|
||||
, OFS_EXTENSIONS
|
||||
}
|
||||
|
||||
iota! {
|
||||
pub const
|
||||
VA_TYPE: usize = iota;
|
||||
, VA_FLAGS
|
||||
, VA_FORMAT
|
||||
, VA_SIZE
|
||||
, VA_OFFSET
|
||||
, VA_FIELD_COUNT
|
||||
}
|
||||
|
||||
iota! {
|
||||
pub const
|
||||
MESH_NAME: usize = iota;
|
||||
, MESH_MATERIAL
|
||||
, MESH_FIRST_VERTEX
|
||||
, MESH_NUM_VERTEXES
|
||||
, MESH_FIRST_TRIANGLE
|
||||
, MESH_NUM_TRIANGLES
|
||||
, MESH_FIELD_COUNT
|
||||
}
|
||||
}
|
||||
|
||||
pub mod types {
|
||||
iota! {
|
||||
pub const POSITION: usize = iota;
|
||||
, TEXCOORD
|
||||
, NORMAL
|
||||
, TANGENT
|
||||
, BLENDINDEXES
|
||||
, BLENDWEIGHTS
|
||||
, COLOR
|
||||
}
|
||||
pub const CUSTOM: usize = 0x10;
|
||||
}
|
||||
|
||||
pub mod formats {
|
||||
iota! {
|
||||
pub const BYTE: u32 = iota;
|
||||
, UBYTE
|
||||
, SHORT
|
||||
, USHORT
|
||||
, INT
|
||||
, UINT
|
||||
, HALF
|
||||
, FLOAT
|
||||
, DOUBLE
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::mem::size_of;
|
||||
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
pub struct Model <'data> {
|
||||
pub data: &'data [u8],
|
||||
}
|
||||
|
||||
pub struct VertexArray <'data> {
|
||||
pub model: &'data Model <'data>,
|
||||
ofs: usize,
|
||||
}
|
||||
|
||||
pub struct Mesh <'data> {
|
||||
pub model: &'data Model <'data>,
|
||||
ofs: 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
|
||||
|
||||
fn usize_from (x: u32) -> usize {
|
||||
usize::try_from (x).unwrap ()
|
||||
}
|
||||
|
||||
impl <'data> Iterator for VertexArrays <'data> {
|
||||
type Item = VertexArray <'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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 vertexarrays (&self) -> VertexArrays {
|
||||
VertexArrays {
|
||||
model: self,
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meshes (&self) -> Meshes {
|
||||
Meshes {
|
||||
model: self,
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'data> VertexArray <'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) -> &[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>()..])
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue