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

@ -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],
}