fix multi mesh models

This commit is contained in:
Robin Appelman 2022-03-12 17:36:14 +01:00
commit 3aa5c8751b
8 changed files with 224 additions and 26 deletions

View file

@ -37,22 +37,41 @@ impl Model {
}
pub fn vertex_strip_indices(&self) -> impl Iterator<Item = impl Iterator<Item = usize> + '_> {
self.vtx
let mdl_meshes = self
.mdl
.body_parts
.iter()
.flat_map(|part| part.models.iter())
.flat_map(|model| model.meshes.iter());
let vtx_meshes = self
.vtx
.body_parts
.iter()
.flat_map(|part| part.models.iter())
.flat_map(|model| model.lods.iter().next())
.flat_map(|lod| lod.meshes.iter())
.flat_map(|mesh| mesh.strip_groups.iter())
.flat_map(|strip_group| {
.flat_map(|lod| lod.meshes.iter());
vtx_meshes
.zip(mdl_meshes)
.flat_map(|(vtx_mesh, mdl_mesh)| {
vtx_mesh
.strip_groups
.iter()
.map(move |strip_group| (strip_group, mdl_mesh))
})
.flat_map(|(strip_group, mdl_mesh)| {
let group_indices = &strip_group.indices;
let vertices = &strip_group.vertices;
let mesh_vertex_offset = mdl_mesh.vertex_offset as usize;
strip_group.strips.iter().cloned().map(move |strip| {
strip
.indices()
.flat_map(|i| i)
.map(move |index| group_indices[index] as usize)
.map(move |index| vertices[index].original_mesh_vertex_id as usize)
.map(move |index| {
vertices[index].original_mesh_vertex_id as usize + mesh_vertex_offset
})
})
})
}

View file

@ -1,26 +1,111 @@
mod bone;
mod header;
mod header2;
mod raw;
pub use bone::*;
pub use header::*;
pub use header2::*;
pub use raw::header::*;
pub use raw::header2::*;
use crate::{read_indexes, ModelError};
use crate::mdl::raw::{BodyPartHeader, Bone, MeshHeader, ModelHeader};
use crate::{read_indexes, FixedString, ModelError};
use binrw::BinReaderExt;
use std::io::Cursor;
type Result<T> = std::result::Result<T, ModelError>;
#[derive(Debug, Clone)]
pub struct Mdl {
pub header: StudioHeader,
pub bones: Vec<Bone>,
pub body_parts: Vec<BodyPart>,
}
impl Mdl {
pub fn read(data: &[u8]) -> Result<Self, ModelError> {
pub fn read(data: &[u8]) -> Result<Self> {
let mut reader = Cursor::new(data);
let header: StudioHeader = reader.read_le()?;
let bones = read_indexes(header.bone_indexes(), data).collect::<Result<_, _>>()?;
Ok(Mdl { header, bones })
let bones = read_indexes(header.bone_indexes(), data).collect::<Result<_>>()?;
Ok(Mdl {
bones,
body_parts: header
.body_part_indexes()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "BodyPart",
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
BodyPart::read(data, header)
})
.collect::<Result<_>>()?,
header,
})
}
}
#[derive(Debug, Clone)]
pub struct BodyPart {
pub name_index: i32,
pub models: Vec<Model>,
}
impl BodyPart {
pub fn read(data: &[u8], header: BodyPartHeader) -> Result<Self> {
Ok(BodyPart {
models: header
.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,
})
}
}
#[derive(Debug, Clone)]
pub struct Model {
pub name: FixedString<64>,
pub ty: i32,
pub bounding_radius: f32,
pub meshes: Vec<Mesh>,
}
impl Model {
pub fn read(data: &[u8], header: ModelHeader) -> Result<Self> {
Ok(Model {
meshes: header
.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,
ty: header.ty,
bounding_radius: header.bounding_radius,
})
}
}
#[derive(Debug, Clone)]
pub struct Mesh {
pub vertex_offset: i32,
}
impl Mesh {
pub fn read(_data: &[u8], header: MeshHeader) -> Result<Self> {
Ok(Mesh {
vertex_offset: header.vertex_index,
})
}
}

View file

@ -1,3 +1,4 @@
use crate::mdl::raw::*;
use crate::mdl::Bone;
use crate::{index_range, FixedString, Vector};
use binrw::BinRead;
@ -219,7 +220,11 @@ impl StudioHeader {
}
pub fn body_part_indexes(&self) -> impl Iterator<Item = usize> {
index_range(self.body_part_offset, self.body_part_count, 1)
index_range(
self.body_part_offset,
self.body_part_count,
size_of::<BodyPartHeader>(),
)
}
pub fn attachment_indexes(&self) -> impl Iterator<Item = usize> {

View file

@ -1,6 +1,11 @@
use crate::{index_range, FixedString};
use crate::{Quaternion, RadianEuler, Vector};
use binrw::BinRead;
use bitflags::bitflags;
use std::mem::size_of;
pub mod header;
pub mod header2;
#[derive(Debug, Clone, BinRead)]
pub struct Bone {
@ -56,3 +61,81 @@ bitflags! {
const BONE_HAS_SAVEFRAME_ROT = 0x00400000;
}
}
#[derive(Debug, Clone, BinRead)]
pub struct BodyPartHeader {
pub name_index: i32,
model_count: i32,
pub base: i32,
model_index: i32,
}
impl BodyPartHeader {
pub fn model_indexes(&self) -> impl Iterator<Item = usize> {
index_range(
self.model_index,
self.model_count,
size_of::<ModelHeader>() - size_of::<FixedString<0>>(),
)
}
}
#[derive(Debug, Clone, BinRead)]
#[allow(dead_code)]
pub struct ModelHeader {
pub name: FixedString<64>,
pub ty: i32,
pub bounding_radius: f32,
mesh_count: i32,
mesh_index: i32,
vertex_count: i32,
vertex_index: i32,
tangent_index: i32,
attachment_count: i32,
attachment_index: i32,
eyeball_count: i32,
eyeball_index: i32,
pub vertex_data: ModelVertexData,
padding: [i32; 8],
}
static_assertions::const_assert_eq!(size_of::<ModelHeader>() - size_of::<FixedString<0>>(), 148);
impl ModelHeader {
pub fn mesh_indexes(&self) -> impl Iterator<Item = usize> {
index_range(self.mesh_index, self.mesh_count, size_of::<MeshHeader>())
}
}
#[derive(Debug, Clone, BinRead)]
#[allow(dead_code)]
pub struct ModelVertexData {
// these are pointers?
vertex_data: i32,
tangent_data: i32,
}
#[derive(Debug, Clone, BinRead)]
#[allow(dead_code)]
pub struct MeshHeader {
material: i32,
model_index: i32,
vertex_count: i32,
pub vertex_index: i32,
flex_count: i32,
flex_index: i32,
material_type: i32,
material_param: i32,
mesh_id: i32,
center: Vector,
vertex_data: MeshVertexData,
padding: [i32; 8],
}
#[derive(Debug, Clone, BinRead)]
#[allow(dead_code)]
pub struct MeshVertexData {
// these are pointers?
model_vertext_data: i32,
lod_vertex_count: [i32; 8],
}

View file

@ -186,7 +186,7 @@ impl StripGroup {
Ok(reader.read_le()?)
})
.collect::<Result<_>>()?,
flags: dbg!(header).flags,
flags: header.flags,
})
}
}
@ -204,7 +204,7 @@ impl Strip {
Ok(Strip {
vertices: header.vertex_indexes(),
indices: header.index_indexes(),
flags: dbg!(header).flags,
flags: header.flags,
})
}

View file

@ -36,6 +36,8 @@ pub struct BodyPartHeader {
model_offset: i32,
}
static_assertions::const_assert_eq!(size_of::<BodyPartHeader>(), 8);
impl BodyPartHeader {
pub fn model_indexes(&self) -> impl Iterator<Item = usize> {
index_range(
@ -52,6 +54,8 @@ pub struct ModelHeader {
lod_offset: i32,
}
static_assertions::const_assert_eq!(size_of::<ModelHeader>(), 8);
impl ModelHeader {
pub fn lod_indexes(&self) -> impl Iterator<Item = usize> {
index_range(self.lod_offset, self.lod_count, size_of::<ModelLodHeader>())
@ -81,6 +85,8 @@ pub struct MeshHeader {
pub flags: MeshFlags,
}
static_assertions::const_assert_eq!(size_of::<MeshHeader>(), 9);
impl MeshHeader {
pub fn strip_group_indexes(&self) -> impl Iterator<Item = usize> {
index_range(