♻️ Extract IQM crate

main
_ 2020-05-25 18:22:06 +00:00
parent cdea0ffbea
commit 6297079ae9
5 changed files with 16 additions and 321 deletions

9
Cargo.lock generated
View File

@ -99,6 +99,14 @@ dependencies = [
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inter_quake_model"
version = "0.1.0"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iota 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "iota"
version = "0.2.1"
@ -209,6 +217,7 @@ dependencies = [
"float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glam 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"inter_quake_model 0.1.0",
"iota 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -23,3 +23,5 @@ partial-min-max = "0.4.0"
png = "0.15.3"
rand = "0.6.5"
sdl2 = "0.32.2"
inter_quake_model = {path = "../inter_quake_model"}

View File

@ -1,314 +0,0 @@
use nom::{
IResult,
bytes::complete::{tag},
number::complete::{le_u32},
};
use std::convert::TryInto;
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 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
}
}
#[derive (Debug)]
pub struct Mesh {
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 Header {
pub fields: [u32; 27],
}
#[derive (Debug)]
pub struct VertexArray {
va_type: u32,
va_flags: u32,
va_format: u32,
va_size: u32,
va_offset: u32,
}
#[derive (Debug)]
pub struct Model <'a> {
data: &'a [u8],
pub header: Header,
text: Vec <u8>,
pub meshes: Vec <Mesh>,
vertexarrays: Vec <VertexArray>,
}
impl Header {
pub fn from_slice (input: &[u8]) -> IResult <&[u8], Header> {
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 field in fields.iter_mut ().skip (1) {
let (i, h) = le_u32 (input)?;
input = i;
*field = h;
}
Ok ((input, Header {
fields,
}))
}
}
impl Mesh {
pub fn from_slice (input: &[u8]) -> IResult <&[u8], Mesh> {
let mut result = Mesh {
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 VertexArray {
pub fn from_slice (input: &[u8]) -> IResult <&[u8], VertexArray> {
let mut result = VertexArray {
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))
}
}
#[derive (Debug)]
pub enum ModelLoadErr {
ParseHeaderFailed,
ParseMeshFailed (usize),
ParseVertexArrayFailed (usize),
}
impl <'a> Model <'a> {
pub fn from_slice (data: &'a [u8]) -> Result <Model <'a>, ModelLoadErr> {
let header = match Header::from_slice (data) {
Ok ((_, h)) => h,
Err (_) => return Err (ModelLoadErr::ParseHeaderFailed),
};
let text = {
let offset: usize = header.fields [consts::OFS_TEXT].try_into ().unwrap ();
let num: usize = header.fields [consts::NUM_TEXT].try_into ().unwrap ();
Vec::from (&data [offset..offset + num])
};
let meshes = {
let num: usize = header.fields [consts::NUM_MESHES].try_into ().unwrap ();
let mut meshes = Vec::with_capacity (num);
let mesh_size = 6 * 4;
let meshes_offset: usize = header.fields [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];
let mesh = match Mesh::from_slice (mesh_slice) {
Ok ((_, m)) => m,
Err (_) => return Err (ModelLoadErr::ParseMeshFailed (i)),
};
meshes.push (mesh);
}
meshes
};
let vertexarrays = {
let num: usize = header.fields [consts::NUM_VERTEXARRAYS].try_into ().unwrap ();
let mut vertexarrays = Vec::with_capacity (num);
let vertexarray_size = 5 * 4;
let vertexarrays_offset: usize = header.fields [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 = match VertexArray::from_slice (vertexarray_slice) {
Ok ((_, va)) => va,
Err (_) => return Err (ModelLoadErr::ParseVertexArrayFailed (i)),
};
vertexarrays.push (vertexarray);
}
vertexarrays
};
Ok (Model {
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 [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 [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]
}
pub fn get_all_indexes (&self) -> &[u8] {
let bytes_per_u32 = 4;
let indexes_per_tri = 3;
let stride = bytes_per_u32 * indexes_per_tri;
let offset: usize = self.header.fields [consts::OFS_TRIANGLES].try_into ().unwrap ();
let num_bytes: usize = (stride * self.header.fields [consts::NUM_TRIANGLES]).try_into ().unwrap ();
&self.data [offset..offset + num_bytes]
}
// I don't think IQM makes any guarantees about UTF-8
// so I will only say that the slice has no NULs
pub fn get_mesh_name (&self, index: usize) -> &[u8] {
let mesh = &self.meshes [index];
let ofs: usize = (self.header.fields [consts::OFS_TEXT] + mesh.name).try_into ().unwrap ();
// There should be an easy way to do this with CString?
let mut nul_index = None;
for (j, c) in self.data [ofs..].iter ().enumerate () {
if *c == 0 {
nul_index = Some (j);
break;
}
}
let nul_index = nul_index.unwrap ();
&self.data [ofs..ofs + nul_index]
}
}

View File

@ -8,7 +8,6 @@ pub mod file;
pub mod glezz;
pub mod gl_state;
pub mod gpu_buffers;
pub mod iqm;
pub mod physics;
pub mod renderable_model;
pub mod shader;

View File

@ -4,7 +4,6 @@ use std::convert::TryInto;
use std::ffi::c_void;
use crate::gpu_buffers::*;
use crate::iqm;
// Takes ownership of mesh stuff in an opaque way that's abstract
// from the IQM model. IQM is zero-copy, but this is not.
@ -49,10 +48,10 @@ pub const
}
impl RenderableModel {
pub fn from_iqm (model: &iqm::Model) -> RenderableModel {
let pos_bytes = model.get_vertex_slice (iqm::types::POSITION);
let uv_bytes = model.get_vertex_slice (iqm::types::TEXCOORD);
let normal_bytes = model.get_vertex_slice (iqm::types::NORMAL);
pub fn from_iqm (model: &inter_quake_model::Model) -> RenderableModel {
let pos_bytes = model.get_vertex_slice (inter_quake_model::types::POSITION);
let uv_bytes = model.get_vertex_slice (inter_quake_model::types::TEXCOORD);
let normal_bytes = model.get_vertex_slice (inter_quake_model::types::NORMAL);
let num_pos = pos_bytes.len () / 4;
let num_uv = uv_bytes.len () / 4;
@ -147,7 +146,7 @@ pub fn renderable_from_iqm_file <P> (filename: P) -> RenderableModel
where P: AsRef <std::path::Path>
{
let data = crate::file::load_small_file (filename, 1024 * 1024).unwrap ();
let model = crate::iqm::Model::from_slice (&data).unwrap ();
let model = inter_quake_model::Model::from_slice (&data).unwrap ();
RenderableModel::from_iqm (&model)
}