From fadf811505355cd5375840e0cb287cf5956682c2 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Tue, 12 Dec 2023 22:13:03 -0500 Subject: [PATCH] Move the model file operations to their own file It helps declutter the already huge model file a bit. --- src/lib.rs | 1 + src/model.rs | 213 +++++------------------------------ src/model_file_operations.rs | 166 +++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 185 deletions(-) create mode 100644 src/model_file_operations.rs diff --git a/src/lib.rs b/src/lib.rs index f0b1328..8f879d0 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,6 +106,7 @@ pub mod pbd; mod crc; mod sha1; +mod model_file_operations; #[doc(hidden)] pub const PHYSIS_VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/model.rs b/src/model.rs index 60390a8..9b3d126 100755 --- a/src/model.rs +++ b/src/model.rs @@ -4,14 +4,11 @@ use std::io::{Cursor, Seek, SeekFrom, Write}; use std::mem::size_of; -use binrw::{BinResult, binrw, BinWrite, BinWriterExt}; +use binrw::{binrw, BinWrite, BinWriterExt}; use binrw::BinRead; use binrw::BinReaderExt; -use half::f16; use crate::{ByteBuffer, ByteSpan}; -// Maximum value of byte, used to divide and multiply floats in that space [0.0..1.0] to [0..255] -const MAX_BYTE_FLOAT: f32 = u8::MAX as f32; // Marker for end of stream (0xFF) const END_OF_STREAM: u8 = 0xFF; @@ -449,12 +446,12 @@ impl MDL { .seek(SeekFrom::Start( (model.lods[i as usize].vertex_data_offset + model.meshes[j as usize].vertex_buffer_offsets - [element.stream as usize] + [element.stream as usize] + element.offset as u32 + model.meshes[j as usize].vertex_buffer_strides - [element.stream as usize] - as u32 - * k as u32) as u64, + [element.stream as usize] + as u32 + * k as u32) as u64, )) .ok()?; @@ -674,25 +671,25 @@ impl MDL { + 4 //StringSize + self.model_data.header.string_size + 56 //ModelHeader - + ( self.model_data.element_ids.len() as u32 * 32 ) - + ( 3 * 60 ) // 3 Lods + + (self.model_data.element_ids.len() as u32 * 32) + + (3 * 60) // 3 Lods //+ ( /*file.ModelHeader.ExtraLodEnabled ? 40*/ 0 ) - + self.model_data.meshes.len() as u32 * 36 - + self.model_data.attribute_name_offsets.len() as u32 * size_of::() as u32 - + self.model_data.header.terrain_shadow_mesh_count as u32 * 20 - + self.model_data.header.submesh_count as u32 * 16 - + self.model_data.header.terrain_shadow_submesh_count as u32 * 10 - + self.model_data.material_name_offsets.len() as u32 * size_of::() as u32 - + self.model_data.bone_name_offsets.len() as u32 * size_of::() as u32 - + self.model_data.bone_tables.len() as u32 * 132 - + self.model_data.header.shape_count as u32 * 16 - + self.model_data.header.shape_mesh_count as u32 * 12 - + self.model_data.header.shape_value_count as u32 * 4 - + 4 // SubmeshBoneMapSize - + self.model_data.submesh_bone_map.len() as u32 * 2 - + 8 // PaddingAmount and Padding - + ( 4 * 32 ) // 4 BoundingBoxes - + ( self.model_data.header.bone_count as u32 * 32 ); + + self.model_data.meshes.len() as u32 * 36 + + self.model_data.attribute_name_offsets.len() as u32 * size_of::() as u32 + + self.model_data.header.terrain_shadow_mesh_count as u32 * 20 + + self.model_data.header.submesh_count as u32 * 16 + + self.model_data.header.terrain_shadow_submesh_count as u32 * 10 + + self.model_data.material_name_offsets.len() as u32 * size_of::() as u32 + + self.model_data.bone_name_offsets.len() as u32 * size_of::() as u32 + + self.model_data.bone_tables.len() as u32 * 132 + + self.model_data.header.shape_count as u32 * 16 + + self.model_data.header.shape_mesh_count as u32 * 12 + + self.model_data.header.shape_value_count as u32 * 4 + + 4 // SubmeshBoneMapSize + + self.model_data.submesh_bone_map.len() as u32 * 2 + + 8 // PaddingAmount and Padding + + (4 * 32) // 4 BoundingBoxes + + (self.model_data.header.bone_count as u32 * 32); let mut vertex_offset = self.file_header.runtime_size + size_of::() as u32 @@ -762,12 +759,12 @@ impl MDL { .seek(SeekFrom::Start( (self.model_data.lods[l].vertex_data_offset + self.model_data.meshes[part.mesh_index as usize].vertex_buffer_offsets - [element.stream as usize] + [element.stream as usize] + element.offset as u32 + self.model_data.meshes[part.mesh_index as usize].vertex_buffer_strides - [element.stream as usize] - as u32 - * k as u32) as u64, + [element.stream as usize] + as u32 + * k as u32) as u64, )) .ok()?; @@ -884,158 +881,4 @@ impl MDL { Some(buffer) } - - fn read_byte_float4(cursor: &mut Cursor) -> Option<[f32; 4]> { - Some([ - (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT), - (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT), - (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT), - (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT) - ]) - } - - fn write_byte_float4(cursor: &mut T, vec: &[f32; 4]) -> BinResult<()> { - cursor.write_le::<[u8; 4]>(&[ - (vec[0] * MAX_BYTE_FLOAT).round() as u8, - (vec[1] * MAX_BYTE_FLOAT).round() as u8, - (vec[2] * MAX_BYTE_FLOAT).round() as u8, - (vec[3] * MAX_BYTE_FLOAT).round() as u8]) - } - - fn read_half4(cursor: &mut Cursor) -> Option<[f32; 4]> { - Some([ - f16::from_bits(cursor.read_le::().ok()?).to_f32(), - f16::from_bits(cursor.read_le::().ok()?).to_f32(), - f16::from_bits(cursor.read_le::().ok()?).to_f32(), - f16::from_bits(cursor.read_le::().ok()?).to_f32() - ]) - } - - fn write_half4(cursor: &mut T, vec: &[f32; 4]) -> BinResult<()> { - cursor.write_le::<[u16; 4]>(&[ - f16::from_f32(vec[0]).to_bits(), - f16::from_f32(vec[1]).to_bits(), - f16::from_f32(vec[2]).to_bits(), - f16::from_f32(vec[3]).to_bits()]) - } - - fn read_uint(cursor: &mut Cursor) -> BinResult<[u8; 4]> { - cursor.read_le::<[u8; 4]>() - } - - fn write_uint(cursor: &mut T, vec: &[u8; 4]) -> BinResult<()> { - cursor.write_le::<[u8; 4]>(vec) - } - - fn read_single3(cursor: &mut Cursor) -> BinResult<[f32; 3]> { - cursor.read_le::<[f32; 3]>() - } - - fn write_single3(cursor: &mut T, vec: &[f32; 3]) -> BinResult<()> { - cursor.write_le::<[f32; 3]>(vec) - } - - fn read_single4(cursor: &mut Cursor) -> BinResult<[f32; 4]> { - cursor.read_le::<[f32; 4]>() - } - - fn write_single4(cursor: &mut T, vec: &[f32; 4]) -> BinResult<()> { - cursor.write_le::<[f32; 4]>(vec) - } - - fn pad_slice(small_slice: &[f32; N], fill: f32) -> [f32; 4] { - let mut bigger_slice: [f32; 4] = [fill, fill, fill, fill]; - bigger_slice[..N].copy_from_slice(&small_slice[..N]); - bigger_slice - } -} - - -#[cfg(test)] -mod tests { - use std::io::Cursor; - use crate::model::MDL; - - macro_rules! assert_delta { - ($x:expr, $y:expr, $d:expr) => { - for i in 0..4 { - if !($x[i] - $y[i] < $d || $y[i] - $x[i] < $d) { panic!(); } - } - } - } - - #[test] - fn byte_float4() { - let a = [0.0, 1.0, 0.5, 0.25]; - - let mut v = vec![]; - let mut cursor = Cursor::new(&mut v); - - MDL::write_byte_float4(&mut cursor, &a).unwrap(); - - let mut read_cursor = Cursor::new(v.as_slice()); - - let b = MDL::read_byte_float4(&mut read_cursor).unwrap(); - assert_delta!(b, a, 0.1); - } - - #[test] - fn half4() { - let a = [0.0, 1.0, 0.5, 0.25]; - - let mut v = vec![]; - let mut cursor = Cursor::new(&mut v); - - MDL::write_half4(&mut cursor, &a).unwrap(); - - let mut read_cursor = Cursor::new(v.as_slice()); - assert_eq!(MDL::read_half4(&mut read_cursor).unwrap(), a); - } - - #[test] - fn uint() { - let a = [5u8, 0u8, 3u8, 15u8]; - - let mut v = vec![]; - let mut cursor = Cursor::new(&mut v); - - MDL::write_uint(&mut cursor, &a).unwrap(); - - let mut read_cursor = Cursor::new(v.as_slice()); - assert_eq!(MDL::read_uint(&mut read_cursor).unwrap(), a); - } - - #[test] - fn single3() { - let a = [3.0, 0.0, -1.0]; - - let mut v = vec![]; - let mut cursor = Cursor::new(&mut v); - - MDL::write_single3(&mut cursor, &a).unwrap(); - - let mut read_cursor = Cursor::new(v.as_slice()); - assert_eq!(MDL::read_single3(&mut read_cursor).unwrap(), a); - } - - #[test] - fn single4() { - let a = [3.0, 0.0, -1.0, 12.0]; - - let mut v = vec![]; - let mut cursor = Cursor::new(&mut v); - - MDL::write_single4(&mut cursor, &a).unwrap(); - - let mut read_cursor = Cursor::new(v.as_slice()); - assert_eq!(MDL::read_single4(&mut read_cursor).unwrap(), a); - } - - #[test] - fn pad_slice() { - let a = [3.0, 0.0, -1.0]; - let b = [3.0, 0.0, -1.0, 1.0]; - - assert_eq!(MDL::pad_slice(&a, 1.0), b); - } -} +} \ No newline at end of file diff --git a/src/model_file_operations.rs b/src/model_file_operations.rs new file mode 100644 index 0000000..213ccaa --- /dev/null +++ b/src/model_file_operations.rs @@ -0,0 +1,166 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +use std::io::Cursor; +use binrw::{BinReaderExt, BinResult, BinWriterExt}; +use half::f16; +use crate::ByteSpan; +use crate::model::MDL; + +// Maximum value of byte, used to divide and multiply floats in that space [0.0..1.0] to [0..255] +const MAX_BYTE_FLOAT: f32 = u8::MAX as f32; + +impl MDL { + pub(crate) fn read_byte_float4(cursor: &mut Cursor) -> Option<[f32; 4]> { + Some([ + (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT), + (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT), + (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT), + (f32::from(cursor.read_le::().ok()?) / MAX_BYTE_FLOAT) + ]) + } + + pub(crate) fn write_byte_float4(cursor: &mut T, vec: &[f32; 4]) -> BinResult<()> { + cursor.write_le::<[u8; 4]>(&[ + (vec[0] * MAX_BYTE_FLOAT).round() as u8, + (vec[1] * MAX_BYTE_FLOAT).round() as u8, + (vec[2] * MAX_BYTE_FLOAT).round() as u8, + (vec[3] * MAX_BYTE_FLOAT).round() as u8]) + } + + pub(crate) fn read_half4(cursor: &mut Cursor) -> Option<[f32; 4]> { + Some([ + f16::from_bits(cursor.read_le::().ok()?).to_f32(), + f16::from_bits(cursor.read_le::().ok()?).to_f32(), + f16::from_bits(cursor.read_le::().ok()?).to_f32(), + f16::from_bits(cursor.read_le::().ok()?).to_f32() + ]) + } + + pub(crate) fn write_half4(cursor: &mut T, vec: &[f32; 4]) -> BinResult<()> { + cursor.write_le::<[u16; 4]>(&[ + f16::from_f32(vec[0]).to_bits(), + f16::from_f32(vec[1]).to_bits(), + f16::from_f32(vec[2]).to_bits(), + f16::from_f32(vec[3]).to_bits()]) + } + + pub(crate) fn read_uint(cursor: &mut Cursor) -> BinResult<[u8; 4]> { + cursor.read_le::<[u8; 4]>() + } + + pub(crate) fn write_uint(cursor: &mut T, vec: &[u8; 4]) -> BinResult<()> { + cursor.write_le::<[u8; 4]>(vec) + } + + pub(crate) fn read_single3(cursor: &mut Cursor) -> BinResult<[f32; 3]> { + cursor.read_le::<[f32; 3]>() + } + + pub(crate) fn write_single3(cursor: &mut T, vec: &[f32; 3]) -> BinResult<()> { + cursor.write_le::<[f32; 3]>(vec) + } + + pub(crate) fn read_single4(cursor: &mut Cursor) -> BinResult<[f32; 4]> { + cursor.read_le::<[f32; 4]>() + } + + pub(crate) fn write_single4(cursor: &mut T, vec: &[f32; 4]) -> BinResult<()> { + cursor.write_le::<[f32; 4]>(vec) + } + + pub(crate) fn pad_slice(small_slice: &[f32; N], fill: f32) -> [f32; 4] { + let mut bigger_slice: [f32; 4] = [fill, fill, fill, fill]; + bigger_slice[..N].copy_from_slice(&small_slice[..N]); + bigger_slice + } +} + +#[cfg(test)] +mod tests { + use std::io::Cursor; + use crate::model::MDL; + + macro_rules! assert_delta { + ($x:expr, $y:expr, $d:expr) => { + for i in 0..4 { + if !($x[i] - $y[i] < $d || $y[i] - $x[i] < $d) { panic!(); } + } + } + } + + #[test] + fn byte_float4() { + let a = [0.0, 1.0, 0.5, 0.25]; + + let mut v = vec![]; + let mut cursor = Cursor::new(&mut v); + + MDL::write_byte_float4(&mut cursor, &a).unwrap(); + + let mut read_cursor = Cursor::new(v.as_slice()); + + let b = MDL::read_byte_float4(&mut read_cursor).unwrap(); + assert_delta!(b, a, 0.1); + } + + #[test] + fn half4() { + let a = [0.0, 1.0, 0.5, 0.25]; + + let mut v = vec![]; + let mut cursor = Cursor::new(&mut v); + + MDL::write_half4(&mut cursor, &a).unwrap(); + + let mut read_cursor = Cursor::new(v.as_slice()); + assert_eq!(MDL::read_half4(&mut read_cursor).unwrap(), a); + } + + #[test] + fn uint() { + let a = [5u8, 0u8, 3u8, 15u8]; + + let mut v = vec![]; + let mut cursor = Cursor::new(&mut v); + + MDL::write_uint(&mut cursor, &a).unwrap(); + + let mut read_cursor = Cursor::new(v.as_slice()); + assert_eq!(MDL::read_uint(&mut read_cursor).unwrap(), a); + } + + #[test] + fn single3() { + let a = [3.0, 0.0, -1.0]; + + let mut v = vec![]; + let mut cursor = Cursor::new(&mut v); + + MDL::write_single3(&mut cursor, &a).unwrap(); + + let mut read_cursor = Cursor::new(v.as_slice()); + assert_eq!(MDL::read_single3(&mut read_cursor).unwrap(), a); + } + + #[test] + fn single4() { + let a = [3.0, 0.0, -1.0, 12.0]; + + let mut v = vec![]; + let mut cursor = Cursor::new(&mut v); + + MDL::write_single4(&mut cursor, &a).unwrap(); + + let mut read_cursor = Cursor::new(v.as_slice()); + assert_eq!(MDL::read_single4(&mut read_cursor).unwrap(), a); + } + + #[test] + fn pad_slice() { + let a = [3.0, 0.0, -1.0]; + let b = [3.0, 0.0, -1.0, 1.0]; + + assert_eq!(MDL::pad_slice(&a, 1.0), b); + } +}