mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
fix multi mesh models
This commit is contained in:
parent
dda97e9856
commit
3aa5c8751b
8 changed files with 224 additions and 26 deletions
29
src/lib.rs
29
src/lib.rs
|
|
@ -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
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
105
src/mdl/mod.rs
105
src/mdl/mod.rs
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
@ -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],
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue