mirror of
https://github.com/redstrate/Physis.git
synced 2025-04-23 13:17:44 +00:00
Simplify PBD parsing
This commit is contained in:
parent
0b77a3cfb0
commit
149e9bb25b
2 changed files with 83 additions and 59 deletions
|
@ -1,6 +1,9 @@
|
|||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use std::io::SeekFrom;
|
||||
use binrw::{BinReaderExt, BinResult};
|
||||
|
||||
pub(crate) fn read_bool_from<T: std::convert::From<u8> + std::cmp::PartialEq>(x: T) -> bool {
|
||||
x == T::from(1u8)
|
||||
}
|
||||
|
@ -13,6 +16,29 @@ pub(crate) fn write_bool_as<T: std::convert::From<u8>>(x: &bool) -> T {
|
|||
}
|
||||
}
|
||||
|
||||
#[binrw::parser(reader, endian)]
|
||||
pub(crate) fn strings_parser(base_offset: u64, strings_offset: &Vec<u16>) -> BinResult<Vec<String>> {
|
||||
let mut strings: Vec<String> =
|
||||
vec![];
|
||||
|
||||
for offset in strings_offset {
|
||||
let string_offset = base_offset + *offset as u64;
|
||||
|
||||
let mut string = String::new();
|
||||
|
||||
reader.seek(SeekFrom::Start(string_offset as u64))?;
|
||||
let mut next_char = reader.read_le::<u8>().unwrap() as char;
|
||||
while next_char != '\0' {
|
||||
string.push(next_char);
|
||||
next_char = reader.read_le::<u8>().unwrap() as char;
|
||||
}
|
||||
|
||||
strings.push(string);
|
||||
}
|
||||
|
||||
Ok(strings)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
116
src/pbd.rs
116
src/pbd.rs
|
@ -4,42 +4,73 @@
|
|||
use std::io::{Cursor, Seek, SeekFrom};
|
||||
|
||||
use crate::ByteSpan;
|
||||
use binrw::binrw;
|
||||
use binrw::{binread, binrw};
|
||||
use binrw::{BinRead, BinReaderExt};
|
||||
use crate::common_file_operations::strings_parser;
|
||||
|
||||
#[binrw]
|
||||
#[binread]
|
||||
#[derive(Debug)]
|
||||
#[br(import { data_offset: i32 })]
|
||||
#[brw(little)]
|
||||
struct RacialDeformer {
|
||||
bone_count: i32,
|
||||
|
||||
#[br(count = bone_count)]
|
||||
bone_name_offsets: Vec<u16>,
|
||||
|
||||
|
||||
#[br(args(data_offset as u64, &bone_name_offsets), parse_with = strings_parser)]
|
||||
#[br(restore_position)]
|
||||
bone_names: Vec<String>,
|
||||
|
||||
#[br(if((bone_count & 1) != 0))]
|
||||
#[br(temp)]
|
||||
_padding: u16,
|
||||
|
||||
/// 4x3 matrix
|
||||
#[br(count = bone_count)]
|
||||
#[br(err_context("offset = {} bone count = {}", data_offset, bone_count))]
|
||||
transform: Vec<[f32; 12]>,
|
||||
|
||||
}
|
||||
|
||||
#[binread]
|
||||
#[derive(Debug)]
|
||||
#[brw(little)]
|
||||
struct PreBoneDeformerItem {
|
||||
body_id: u16,
|
||||
link_index: u16,
|
||||
body_id: u16, // the combined body id like 0101
|
||||
link_index: i16,
|
||||
#[br(pad_after = 4)]
|
||||
data_offset: u32,
|
||||
#[br(temp)]
|
||||
data_offset: i32,
|
||||
|
||||
#[br(args { data_offset: data_offset })]
|
||||
#[br(seek_before = SeekFrom::Start(data_offset as u64))]
|
||||
#[br(restore_position)]
|
||||
deformer: RacialDeformer
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[binread]
|
||||
#[derive(Debug)]
|
||||
#[brw(little)]
|
||||
struct PreBoneDeformerLink {
|
||||
#[br(pad_after = 4)]
|
||||
next_index: i16,
|
||||
next_item_index: u16,
|
||||
parent_index: i16,
|
||||
first_child_index: i16,
|
||||
next_sibling_index: i16,
|
||||
deformer_index: u16,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[binread]
|
||||
#[derive(Debug)]
|
||||
#[brw(little)]
|
||||
struct PreBoneDeformerHeader {
|
||||
count: u32,
|
||||
count: i32,
|
||||
|
||||
#[br(count = count)]
|
||||
items: Vec<PreBoneDeformerItem>,
|
||||
|
||||
#[br(count = count)]
|
||||
links: Vec<PreBoneDeformerLink>,
|
||||
|
||||
#[br(ignore)]
|
||||
raw_data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct PreBoneDeformer {
|
||||
|
@ -64,9 +95,7 @@ impl PreBoneDeformer {
|
|||
/// Reads an existing PBD file
|
||||
pub fn from_existing(buffer: ByteSpan) -> Option<PreBoneDeformer> {
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let mut header = PreBoneDeformerHeader::read(&mut cursor).ok()?;
|
||||
|
||||
header.raw_data = buffer.to_vec();
|
||||
let mut header = PreBoneDeformerHeader::read(&mut cursor).unwrap();
|
||||
|
||||
Some(PreBoneDeformer { header })
|
||||
}
|
||||
|
@ -88,57 +117,26 @@ impl PreBoneDeformer {
|
|||
.find(|x| x.body_id == from_body_id)?;
|
||||
let mut next = &self.header.links[item.link_index as usize];
|
||||
|
||||
if next.next_index == -1 {
|
||||
if next.next_sibling_index == -1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut bones = vec![];
|
||||
|
||||
let mut cursor = Cursor::new(&self.header.raw_data);
|
||||
|
||||
loop {
|
||||
cursor.seek(SeekFrom::Start(item.data_offset as u64)).ok()?;
|
||||
let bone_name_count = cursor.read_le::<u32>().unwrap() as usize;
|
||||
|
||||
let string_offsets_base = item.data_offset as usize + core::mem::size_of::<u32>();
|
||||
|
||||
cursor
|
||||
.seek(SeekFrom::Start(string_offsets_base as u64))
|
||||
.ok()?;
|
||||
let mut strings_offset = vec![];
|
||||
for _ in 0..bone_name_count {
|
||||
strings_offset.push(cursor.read_le::<u16>().unwrap());
|
||||
}
|
||||
|
||||
let matrices_base = string_offsets_base + (bone_name_count + bone_name_count % 2) * 2;
|
||||
cursor.seek(SeekFrom::Start(matrices_base as u64)).ok()?;
|
||||
|
||||
let mut matrices = vec![];
|
||||
for _ in 0..bone_name_count {
|
||||
matrices.push(cursor.read_le::<[f32; 12]>().unwrap());
|
||||
}
|
||||
|
||||
for i in 0..bone_name_count {
|
||||
let string_offset = item.data_offset as usize + strings_offset[i] as usize;
|
||||
|
||||
let mut string = String::new();
|
||||
|
||||
cursor.seek(SeekFrom::Start(string_offset as u64)).ok()?;
|
||||
let mut next_char = cursor.read_le::<u8>().unwrap() as char;
|
||||
while next_char != '\0' {
|
||||
string.push(next_char);
|
||||
next_char = cursor.read_le::<u8>().unwrap() as char;
|
||||
}
|
||||
|
||||
let matrix = matrices[i];
|
||||
for i in 0..item.deformer.bone_count {
|
||||
bones.push(PreBoneDeformBone {
|
||||
name: string,
|
||||
deform: matrix,
|
||||
});
|
||||
name: item.deformer.bone_names[i as usize].clone(),
|
||||
deform: item.deformer.transform[i as usize],
|
||||
})
|
||||
}
|
||||
|
||||
next = &self.header.links[next.next_index as usize];
|
||||
item = &self.header.items[next.next_item_index as usize];
|
||||
if next.parent_index == -1 {
|
||||
break;
|
||||
}
|
||||
|
||||
next = &self.header.links[next.parent_index as usize];
|
||||
item = &self.header.items[next.deformer_index as usize];
|
||||
|
||||
if item.body_id == to_body_id {
|
||||
break;
|
||||
|
|
Loading…
Add table
Reference in a new issue