mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
fully switch to bytemuck for reading
This commit is contained in:
parent
473d6eecc5
commit
bb4dfddde2
11 changed files with 38 additions and 130 deletions
|
|
@ -6,7 +6,6 @@ exclude = ["data"]
|
|||
|
||||
[dependencies]
|
||||
arrayvec = "0.7.2"
|
||||
binrw = "0.8.0"
|
||||
thiserror = "1.0.30"
|
||||
static_assertions = "1.1.0"
|
||||
bitflags = "1.0.4"
|
||||
|
|
|
|||
21
src/error.rs
21
src/error.rs
|
|
@ -7,31 +7,10 @@ pub enum ModelError {
|
|||
IO(#[from] std::io::Error),
|
||||
#[error(transparent)]
|
||||
String(#[from] StringError),
|
||||
#[error("Malformed field found while parsing: {0:#}")]
|
||||
MalformedData(binrw::Error),
|
||||
#[error("referenced data to {data} is out of bounds at {offset}")]
|
||||
OutOfBounds { data: &'static str, offset: usize },
|
||||
}
|
||||
|
||||
impl From<binrw::Error> for ModelError {
|
||||
fn from(e: binrw::Error) -> Self {
|
||||
use binrw::Error;
|
||||
|
||||
// only a few error types should be generated by our code
|
||||
match e {
|
||||
Error::Io(e) => ModelError::IO(e),
|
||||
Error::Custom { err, .. } => {
|
||||
if err.is::<StringError>() {
|
||||
ModelError::String(*err.downcast::<StringError>().unwrap())
|
||||
} else {
|
||||
panic!("unexpected custom error")
|
||||
}
|
||||
}
|
||||
e => ModelError::MalformedData(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum StringError {
|
||||
#[error(transparent)]
|
||||
|
|
|
|||
16
src/lib.rs
16
src/lib.rs
|
|
@ -8,13 +8,11 @@ pub mod vvd;
|
|||
use crate::mdl::Mdl;
|
||||
use crate::vtx::Vtx;
|
||||
use crate::vvd::{Vertex, Vvd};
|
||||
use binrw::{BinRead, BinReaderExt};
|
||||
use bytemuck::{pod_read_unaligned, Pod};
|
||||
pub use error::*;
|
||||
pub use handle::Handle;
|
||||
pub use shared::*;
|
||||
use std::any::type_name;
|
||||
use std::io::Cursor;
|
||||
use std::mem::size_of;
|
||||
|
||||
pub struct Model {
|
||||
|
|
@ -82,13 +80,10 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_indexes<'a, I: Iterator<Item = usize> + 'static, T: BinRead>(
|
||||
fn read_indexes<'a, I: Iterator<Item = usize> + 'static, T: Readable>(
|
||||
indexes: I,
|
||||
data: &'a [u8],
|
||||
) -> impl Iterator<Item = Result<T, ModelError>> + 'a
|
||||
where
|
||||
T::Args: Default,
|
||||
{
|
||||
) -> impl Iterator<Item = Result<T, ModelError>> + 'a {
|
||||
indexes
|
||||
.map(|index| {
|
||||
data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
|
||||
|
|
@ -96,12 +91,7 @@ where
|
|||
offset: index,
|
||||
})
|
||||
})
|
||||
.map(|data| {
|
||||
data.and_then(|data| {
|
||||
let mut cursor = Cursor::new(data);
|
||||
cursor.read_le().map_err(ModelError::from)
|
||||
})
|
||||
})
|
||||
.map(|data| data.and_then(|data| T::read(data)))
|
||||
}
|
||||
|
||||
fn index_range(index: i32, count: i32, size: usize) -> impl Iterator<Item = usize> {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ pub use raw::header2::*;
|
|||
|
||||
use crate::mdl::raw::{BodyPartHeader, Bone, MeshHeader, ModelHeader};
|
||||
use crate::{read_indexes, read_relative, FixedString, ModelError, ReadRelative, Readable};
|
||||
use binrw::BinReaderExt;
|
||||
use std::io::Cursor;
|
||||
|
||||
type Result<T> = std::result::Result<T, ModelError>;
|
||||
|
||||
|
|
@ -19,8 +17,7 @@ pub struct Mdl {
|
|||
|
||||
impl Mdl {
|
||||
pub fn read(data: &[u8]) -> Result<Self> {
|
||||
let mut reader = Cursor::new(data);
|
||||
let header: StudioHeader = reader.read_le()?;
|
||||
let header = <StudioHeader as Readable>::read(data)?;
|
||||
let bones = read_indexes(header.bone_indexes(), data).collect::<Result<_>>()?;
|
||||
Ok(Mdl {
|
||||
bones,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
use crate::mdl::raw::*;
|
||||
use crate::mdl::Bone;
|
||||
use crate::{index_range, FixedString, Vector};
|
||||
use binrw::BinRead;
|
||||
use crate::{index_range, Vector};
|
||||
use std::mem::size_of;
|
||||
|
||||
pub const FILETYPE_ID: i32 = i32::from_be_bytes(*b"IDST");
|
||||
pub const MDL_VERSION: i32 = 48;
|
||||
|
||||
#[derive(Debug, Clone, BinRead)]
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct StudioHeader {
|
||||
pub id: i32,
|
||||
pub version: i32,
|
||||
pub checksum: [u8; 4], // This has to be the same in the phy and vtx files to load!
|
||||
pub name: FixedString<64>,
|
||||
pub name: [u8; 64],
|
||||
pub data_length: i32,
|
||||
|
||||
pub eye_position: Vector, // Position of player viewpoint relative to model origin
|
||||
|
|
@ -175,7 +175,8 @@ pub struct StudioHeader {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(BinRead)]
|
||||
#[derive(Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct ModelFlags: u32 {
|
||||
const AUTOGENERATED_HITBOX = 0x00000001;
|
||||
const USES_ENV_CUBEMAP = 0x00000002;
|
||||
|
|
@ -308,4 +309,4 @@ impl StudioHeader {
|
|||
}
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(size_of::<StudioHeader>() - size_of::<FixedString<0>>(), 408);
|
||||
static_assertions::const_assert_eq!(size_of::<StudioHeader>(), 408);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::{index_range, FixedString, Pod};
|
||||
use crate::{index_range, FixedString};
|
||||
use crate::{Quaternion, RadianEuler, Vector};
|
||||
use binrw::BinRead;
|
||||
use bitflags::bitflags;
|
||||
use bytemuck::Zeroable;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::mem::size_of;
|
||||
|
||||
pub mod header;
|
||||
pub mod header2;
|
||||
|
||||
#[derive(Debug, Clone, BinRead)]
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct Bone {
|
||||
pub sz_name_index: i32,
|
||||
pub parent: i32, // parent bone
|
||||
|
|
@ -34,7 +34,8 @@ pub struct Bone {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(BinRead)]
|
||||
#[derive(Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct BoneFlags: u32 {
|
||||
const BONE_PHYSICALLY_SIMULATED = 0x00000001;
|
||||
const BONE_PHYSICS_PROCEDURAL = 0x00000002;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::{BinRead, ModelError, StringError};
|
||||
use crate::{ModelError, StringError};
|
||||
use arrayvec::ArrayString;
|
||||
use binrw::{BinResult, ReadOptions};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Add;
|
||||
|
||||
#[derive(Debug, Clone, Copy, BinRead, Zeroable, Pod)]
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct Vector {
|
||||
pub x: f32,
|
||||
|
|
@ -54,7 +53,8 @@ impl Add<Vector> for Vector {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, BinRead)]
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct Quaternion {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
|
|
@ -62,7 +62,8 @@ pub struct Quaternion {
|
|||
pub w: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, BinRead)]
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct RadianEuler {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
|
|
@ -107,38 +108,3 @@ impl<const LEN: usize> Display for FixedString<LEN> {
|
|||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> BinRead for FixedString<LEN> {
|
||||
type Args = ();
|
||||
|
||||
fn read_options<R: binrw::io::Read + binrw::io::Seek>(
|
||||
reader: &mut R,
|
||||
options: &ReadOptions,
|
||||
args: Self::Args,
|
||||
) -> BinResult<Self> {
|
||||
use std::str;
|
||||
|
||||
let name_buf = <[u8; LEN]>::read_options(reader, options, args)?;
|
||||
|
||||
let zero_pos =
|
||||
name_buf
|
||||
.iter()
|
||||
.position(|c| *c == 0)
|
||||
.ok_or_else(|| binrw::Error::Custom {
|
||||
pos: reader.stream_position().unwrap(),
|
||||
err: Box::new(StringError::NotNullTerminated),
|
||||
})?;
|
||||
let name = &name_buf[..zero_pos];
|
||||
Ok(FixedString(
|
||||
ArrayString::from(
|
||||
str::from_utf8(name)
|
||||
.map_err(StringError::NonUTF8)
|
||||
.map_err(|e| binrw::Error::Custom {
|
||||
pos: reader.stream_position().unwrap(),
|
||||
err: Box::new(e),
|
||||
})?,
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
mod raw;
|
||||
|
||||
use crate::{read_relative, ModelError, ReadRelative};
|
||||
use binrw::BinReaderExt;
|
||||
use crate::{read_relative, ModelError, ReadRelative, Readable};
|
||||
use itertools::Either;
|
||||
use raw::*;
|
||||
pub use raw::{MeshFlags, StripFlags, StripGroupFlags, Vertex};
|
||||
use std::io::Cursor;
|
||||
use std::ops::Range;
|
||||
|
||||
pub const MDL_VERSION: i32 = 7;
|
||||
|
|
@ -20,8 +18,7 @@ pub struct Vtx {
|
|||
|
||||
impl Vtx {
|
||||
pub fn read(data: &[u8]) -> Result<Self> {
|
||||
let mut reader = Cursor::new(data);
|
||||
let header: VtxHeader = reader.read_le()?;
|
||||
let header = <VtxHeader as Readable>::read(data)?;
|
||||
Ok(Vtx {
|
||||
body_parts: read_relative(data, header.body_indexes())?,
|
||||
header,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::{index_range, Pod};
|
||||
use binrw::BinRead;
|
||||
use bitflags::bitflags;
|
||||
use bytemuck::Zeroable;
|
||||
use std::mem::size_of;
|
||||
use std::ops::Range;
|
||||
|
||||
#[derive(Debug, Clone, BinRead)]
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct VtxHeader {
|
||||
pub version: i32,
|
||||
pub vertex_cache_size: i32,
|
||||
|
|
@ -103,7 +103,7 @@ impl MeshHeader {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(BinRead, Zeroable, Pod)]
|
||||
#[derive(Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct MeshFlags: u8 {
|
||||
const IS_TEETH = 0x01;
|
||||
|
|
@ -150,7 +150,7 @@ impl StripGroupHeader {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(BinRead, Zeroable, Pod)]
|
||||
#[derive(Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct StripGroupFlags: u8 {
|
||||
const IS_FLEXED = 0x01;
|
||||
|
|
@ -177,7 +177,7 @@ pub struct StripHeader {
|
|||
static_assertions::const_assert_eq!(size_of::<StripHeader>(), 27);
|
||||
|
||||
bitflags! {
|
||||
#[derive(BinRead, Zeroable, Pod)]
|
||||
#[derive(Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct StripFlags: u8 {
|
||||
const IS_TRI_LIST = 0x01;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
mod raw;
|
||||
|
||||
use crate::vvd::raw::{VertexFileFixup, VvdHeader};
|
||||
use crate::{read_relative, read_relative_iter, ModelError};
|
||||
use binrw::BinReaderExt;
|
||||
use crate::{read_relative, read_relative_iter, ModelError, Readable};
|
||||
pub use raw::{BoneWeight, Tangent, Vertex};
|
||||
use std::io::Cursor;
|
||||
|
||||
type Result<T> = std::result::Result<T, ModelError>;
|
||||
|
||||
|
|
@ -16,8 +14,7 @@ pub struct Vvd {
|
|||
|
||||
impl Vvd {
|
||||
pub fn read(data: &[u8]) -> Result<Self> {
|
||||
let mut reader = Cursor::new(data);
|
||||
let header: VvdHeader = reader.read_le()?;
|
||||
let header = <VvdHeader as Readable>::read(data)?;
|
||||
let source_vertices = read_relative(data, header.vertex_indexes(0).unwrap())?;
|
||||
let vertices = if !header.has_fixups() {
|
||||
source_vertices
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use crate::{index_range, Vector};
|
||||
use binrw::{BinRead, BinResult, ReadOptions};
|
||||
use bytemuck::{cast, Pod, Zeroable};
|
||||
use std::io::{Read, Seek};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::mem::size_of;
|
||||
|
||||
#[derive(Debug, Clone, BinRead)]
|
||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct VvdHeader {
|
||||
pub id: i32,
|
||||
pub version: i32,
|
||||
|
|
@ -44,7 +43,7 @@ impl VvdHeader {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, BinRead, Zeroable, Pod, Copy)]
|
||||
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct VertexFileFixup {
|
||||
pub lod: i32,
|
||||
|
|
@ -62,26 +61,8 @@ pub struct Vertex {
|
|||
}
|
||||
|
||||
static_assertions::const_assert_eq!(size_of::<Vertex>(), 48);
|
||||
// binread_for_pod!(Vertex);
|
||||
|
||||
impl BinRead for Vertex {
|
||||
type Args = ();
|
||||
|
||||
fn read_options<R: Read + Seek>(
|
||||
reader: &mut R,
|
||||
_options: &ReadOptions,
|
||||
_args: Self::Args,
|
||||
) -> BinResult<Self> {
|
||||
let mut bytes = unsafe {
|
||||
std::mem::MaybeUninit::<[u8; std::mem::size_of::<Self>()]>::uninit().assume_init()
|
||||
};
|
||||
|
||||
reader.read(&mut bytes)?;
|
||||
Ok(cast(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, BinRead, Zeroable, Pod, Copy)]
|
||||
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct BoneWeight {
|
||||
pub weight: [f32; 3],
|
||||
|
|
@ -91,7 +72,7 @@ pub struct BoneWeight {
|
|||
|
||||
static_assertions::const_assert_eq!(size_of::<BoneWeight>(), 16);
|
||||
|
||||
#[derive(Debug, Clone, BinRead, Zeroable, Pod, Copy)]
|
||||
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct Tangent {
|
||||
pub x: f32,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue