diff --git a/src/lib.rs b/src/lib.rs index 15ca37d..9b69fa8 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,6 +76,10 @@ pub mod tex; #[cfg(feature = "visual_data")] pub mod mtrl; +/// Reading shader packages (SHPK) +#[cfg(feature = "visual_data")] +pub mod shpk; + /// Reading character parameter files (CMP) pub mod cmp; diff --git a/src/shpk.rs b/src/shpk.rs new file mode 100644 index 0000000..a279c8e --- /dev/null +++ b/src/shpk.rs @@ -0,0 +1,85 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +use std::io::{Cursor, Seek, SeekFrom}; + +use binrw::{BinRead, binread, BinReaderExt}; + +use crate::gamedata::MemoryBuffer; + +#[binread] +#[br(little)] +#[br(magic = b"ShPk")] +#[derive(Debug)] +struct SHPKHeader { + #[br(pad_before = 4)] // what are these bytes? 01 0B + #[br(count = 4)] + #[bw(pad_size_to = 4)] + #[bw(map = |x : &String | x.as_bytes())] + #[br(map = | x: Vec | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())] + format: String, + + file_length: i32, + shader_data_offset: i32, + parameter_list_offset: i32, + vertex_shader_count: i32, + pixel_shader_count: i32, + scalar_parameter_count: i32, + resource_parameter_count: i32 +} + +pub struct Shader { + pub bytecode: Vec +} + +pub struct ShaderPackage { + pub vertex_shaders: Vec, + pub pixel_shaders: Vec +} + +impl ShaderPackage { + pub fn from_existing(buffer: &MemoryBuffer) -> Option { + let mut cursor = Cursor::new(buffer); + let header = SHPKHeader::read(&mut cursor).ok()?; + + // start of shader data + cursor.seek(SeekFrom::Start(header.shader_data_offset as u64 + 12)).ok()?; + + let mut vertex_shaders: Vec = Vec::new(); + let mut pixel_shaders: Vec = Vec::new(); + + let mut buffer: Vec = Vec::new(); + let eof_magic = 1128421444u32; + + while vertex_shaders.len() < header.vertex_shader_count as usize { + let word = cursor.read_le::().unwrap(); + + if word == eof_magic && !buffer.is_empty() { + vertex_shaders.push(Shader { + bytecode: buffer.clone() + }); + buffer.clear(); + } else { + buffer.extend_from_slice(word.to_le_bytes().as_slice()); + } + } + + while pixel_shaders.len() < header.pixel_shader_count as usize { + let word = cursor.read_le::().unwrap(); + + if word == eof_magic && !buffer.is_empty() || cursor.position() == header.parameter_list_offset as u64 { + pixel_shaders.push(Shader { + bytecode: buffer.clone() + }); + buffer.clear(); + } else { + buffer.extend_from_slice(word.to_le_bytes().as_slice()); + } + } + + Some(ShaderPackage { + vertex_shaders, + pixel_shaders + }) + } +}