inter_quake_model/src/zero_copy.rs

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>()..])
}
}