♻️ Extract IQM crate
parent
cdea0ffbea
commit
6297079ae9
|
@ -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)",
|
||||
|
|
|
@ -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"}
|
||||
|
|
314
src/iqm.rs
314
src/iqm.rs
|
@ -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]
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue