refactor relative reading

This commit is contained in:
Robin Appelman 2022-03-12 18:07:59 +01:00
commit bb28ec14ea
4 changed files with 98 additions and 134 deletions

View file

@ -37,12 +37,18 @@ impl Model {
} }
pub fn vertex_strip_indices(&self) -> impl Iterator<Item = impl Iterator<Item = usize> + '_> { pub fn vertex_strip_indices(&self) -> impl Iterator<Item = impl Iterator<Item = usize> + '_> {
let mdl_meshes = self let mesh_vertex_offsets = self
.mdl .mdl
.body_parts .body_parts
.iter() .iter()
.flat_map(|part| part.models.iter()) .flat_map(|part| part.models.iter())
.flat_map(|model| model.meshes.iter()); .flat_map(|model| {
model
.meshes
.iter()
.map(move |mesh| (mesh, model.vertex_offset))
})
.map(|(mesh, offset)| (mesh.vertex_offset + offset) as usize);
let vtx_meshes = self let vtx_meshes = self
.vtx .vtx
@ -53,17 +59,16 @@ impl Model {
.flat_map(|lod| lod.meshes.iter()); .flat_map(|lod| lod.meshes.iter());
vtx_meshes vtx_meshes
.zip(mdl_meshes) .zip(mesh_vertex_offsets)
.flat_map(|(vtx_mesh, mdl_mesh)| { .flat_map(|(vtx_mesh, vertex_offset)| {
vtx_mesh vtx_mesh
.strip_groups .strip_groups
.iter() .iter()
.map(move |strip_group| (strip_group, mdl_mesh)) .map(move |strip_group| (strip_group, vertex_offset))
}) })
.flat_map(|(strip_group, mdl_mesh)| { .flat_map(|(strip_group, mesh_vertex_offset)| {
let group_indices = &strip_group.indices; let group_indices = &strip_group.indices;
let vertices = &strip_group.vertices; let vertices = &strip_group.vertices;
let mesh_vertex_offset = mdl_mesh.vertex_offset as usize;
strip_group.strips.iter().cloned().map(move |strip| { strip_group.strips.iter().cloned().map(move |strip| {
strip strip
.indices() .indices()
@ -104,3 +109,37 @@ fn index_range(index: i32, count: i32, size: usize) -> impl Iterator<Item = usiz
.map(move |i| i * size) .map(move |i| i * size)
.map(move |i| index as usize + i) .map(move |i| index as usize + i)
} }
fn read_relative<T: ReadRelative, I: Iterator<Item = usize>>(
data: &[u8],
indexes: I,
) -> Result<Vec<T>, ModelError>
where
<<T as ReadRelative>::Header as BinRead>::Args: Default,
{
indexes
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: type_name::<T>(),
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
T::read(data, header)
})
.collect()
}
trait ReadRelative: Sized {
type Header: BinRead;
fn read(data: &[u8], header: Self::Header) -> Result<Self, ModelError>;
}
impl<T: BinRead> ReadRelative for T {
type Header = T;
fn read(_data: &[u8], header: Self::Header) -> Result<Self, ModelError> {
Ok(header)
}
}

View file

@ -4,7 +4,7 @@ pub use raw::header::*;
pub use raw::header2::*; pub use raw::header2::*;
use crate::mdl::raw::{BodyPartHeader, Bone, MeshHeader, ModelHeader}; use crate::mdl::raw::{BodyPartHeader, Bone, MeshHeader, ModelHeader};
use crate::{read_indexes, FixedString, ModelError}; use crate::{read_indexes, read_relative, FixedString, ModelError, ReadRelative};
use binrw::BinReaderExt; use binrw::BinReaderExt;
use std::io::Cursor; use std::io::Cursor;
@ -47,21 +47,12 @@ pub struct BodyPart {
pub models: Vec<Model>, pub models: Vec<Model>,
} }
impl BodyPart { impl ReadRelative for BodyPart {
pub fn read(data: &[u8], header: BodyPartHeader) -> Result<Self> { type Header = BodyPartHeader;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(BodyPart { Ok(BodyPart {
models: header models: read_relative(data, header.model_indexes())?,
.model_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "Model",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
Model::read(data, header)
})
.collect::<Result<_>>()?,
name_index: header.name_index, name_index: header.name_index,
}) })
} }
@ -73,26 +64,19 @@ pub struct Model {
pub ty: i32, pub ty: i32,
pub bounding_radius: f32, pub bounding_radius: f32,
pub meshes: Vec<Mesh>, pub meshes: Vec<Mesh>,
pub vertex_offset: i32,
} }
impl Model { impl ReadRelative for Model {
pub fn read(data: &[u8], header: ModelHeader) -> Result<Self> { type Header = ModelHeader;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(Model { Ok(Model {
meshes: header meshes: read_relative(data, header.mesh_indexes())?,
.mesh_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "Mesh",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
Mesh::read(data, header)
})
.collect::<Result<_>>()?,
name: header.name, name: header.name,
ty: header.ty, ty: header.ty,
bounding_radius: header.bounding_radius, bounding_radius: header.bounding_radius,
vertex_offset: header.vertex_index,
}) })
} }
} }
@ -102,8 +86,10 @@ pub struct Mesh {
pub vertex_offset: i32, pub vertex_offset: i32,
} }
impl Mesh { impl ReadRelative for Mesh {
pub fn read(_data: &[u8], header: MeshHeader) -> Result<Self> { type Header = MeshHeader;
fn read(_data: &[u8], header: Self::Header) -> Result<Self> {
Ok(Mesh { Ok(Mesh {
vertex_offset: header.vertex_index, vertex_offset: header.vertex_index,
}) })

View file

@ -89,7 +89,7 @@ pub struct ModelHeader {
mesh_count: i32, mesh_count: i32,
mesh_index: i32, mesh_index: i32,
vertex_count: i32, vertex_count: i32,
vertex_index: i32, pub vertex_index: i32,
tangent_index: i32, tangent_index: i32,
attachment_count: i32, attachment_count: i32,
attachment_index: i32, attachment_index: i32,

View file

@ -1,6 +1,6 @@
mod raw; mod raw;
use crate::ModelError; use crate::{read_relative, ModelError, ReadRelative};
use binrw::BinReaderExt; use binrw::BinReaderExt;
use itertools::Either; use itertools::Either;
use raw::*; use raw::*;
@ -45,21 +45,12 @@ pub struct BodyPart {
pub models: Vec<Model>, pub models: Vec<Model>,
} }
impl BodyPart { impl ReadRelative for BodyPart {
fn read(data: &[u8], header: BodyPartHeader) -> Result<Self> { type Header = BodyPartHeader;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(BodyPart { Ok(BodyPart {
models: header models: read_relative(data, header.model_indexes())?,
.model_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "Model",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
Model::read(data, header)
})
.collect::<Result<_>>()?,
}) })
} }
} }
@ -69,21 +60,12 @@ pub struct Model {
pub lods: Vec<ModelLod>, pub lods: Vec<ModelLod>,
} }
impl Model { impl ReadRelative for Model {
fn read(data: &[u8], header: ModelHeader) -> Result<Self> { type Header = ModelHeader;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(Model { Ok(Model {
lods: header lods: read_relative(data, header.lod_indexes())?,
.lod_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "ModelLod",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
ModelLod::read(data, header)
})
.collect::<Result<_>>()?,
}) })
} }
} }
@ -94,21 +76,12 @@ pub struct ModelLod {
pub switch_point: f32, pub switch_point: f32,
} }
impl ModelLod { impl ReadRelative for ModelLod {
fn read(data: &[u8], header: ModelLodHeader) -> Result<Self> { type Header = ModelLodHeader;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(ModelLod { Ok(ModelLod {
meshes: header meshes: read_relative(data, header.mesh_indexes())?,
.mesh_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "Mesh",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
Mesh::read(data, header)
})
.collect::<Result<_>>()?,
switch_point: header.switch_point, switch_point: header.switch_point,
}) })
} }
@ -120,21 +93,12 @@ pub struct Mesh {
pub flags: MeshFlags, pub flags: MeshFlags,
} }
impl Mesh { impl ReadRelative for Mesh {
fn read(data: &[u8], header: MeshHeader) -> Result<Self> { type Header = MeshHeader;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(Mesh { Ok(Mesh {
strip_groups: header strip_groups: read_relative(data, header.strip_group_indexes())?,
.strip_group_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "StripGroup",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
StripGroup::read(data, header)
})
.collect::<Result<_>>()?,
flags: header.flags, flags: header.flags,
}) })
} }
@ -149,43 +113,14 @@ pub struct StripGroup {
pub flags: StripGroupFlags, pub flags: StripGroupFlags,
} }
impl StripGroup { impl ReadRelative for StripGroup {
fn read(data: &[u8], header: StripGroupHeader) -> Result<Self> { type Header = StripGroupHeader;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(StripGroup { Ok(StripGroup {
vertices: header vertices: read_relative(data, header.vertex_indexes())?,
.vertex_indexes() strips: read_relative(data, header.strip_indexes())?,
.map(|index| { indices: read_relative(data, header.index_indexes())?,
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "Vertex",
offset: index,
})?;
let mut reader = Cursor::new(data);
reader.read_le().map_err(ModelError::from)
})
.collect::<Result<_>>()?,
strips: header
.strip_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "Strip",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
Strip::read(data, header)
})
.collect::<Result<_>>()?,
indices: header
.index_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "VertexIndex",
offset: index,
})?;
let mut reader = Cursor::new(data);
Ok(reader.read_le()?)
})
.collect::<Result<_>>()?,
flags: header.flags, flags: header.flags,
}) })
} }
@ -199,15 +134,19 @@ pub struct Strip {
indices: Range<usize>, indices: Range<usize>,
} }
impl Strip { impl ReadRelative for Strip {
fn read(_data: &[u8], header: StripHeader) -> Result<Self> { type Header = StripHeader;
fn read(_data: &[u8], header: Self::Header) -> Result<Self> {
Ok(Strip { Ok(Strip {
vertices: header.vertex_indexes(), vertices: header.vertex_indexes(),
indices: header.index_indexes(), indices: header.index_indexes(),
flags: header.flags, flags: header.flags,
}) })
} }
}
impl Strip {
pub fn vertices(&self) -> impl Iterator<Item = usize> + 'static { pub fn vertices(&self) -> impl Iterator<Item = usize> + 'static {
self.vertices.clone() self.vertices.clone()
} }