|
|
|
@ -1,8 +1,8 @@
|
|
|
|
|
use crate::{ |
|
|
|
|
data::{read, vertex::Vertex}, |
|
|
|
|
ffi, |
|
|
|
|
math::*, |
|
|
|
|
}; |
|
|
|
|
use glam::{Mat4, Quat, Vec3, Vec3A, Vec4}; |
|
|
|
|
use smol_str::SmolStr; |
|
|
|
|
use std::{ |
|
|
|
|
collections::HashMap, |
|
|
|
@ -27,6 +27,8 @@ pub enum Err {
|
|
|
|
|
Parent, |
|
|
|
|
#[error("Bad frame count")] |
|
|
|
|
FrameCount, |
|
|
|
|
#[error("Inverse of matrix not possible")] |
|
|
|
|
Inverse, |
|
|
|
|
#[error("Unknown vertex array type")] |
|
|
|
|
VaType, |
|
|
|
|
#[error("Unsupported vertex array format")] |
|
|
|
@ -35,27 +37,34 @@ pub enum Err {
|
|
|
|
|
|
|
|
|
|
struct VertexZipper { |
|
|
|
|
// kono jippa......
|
|
|
|
|
pos_v: std::vec::IntoIter<Vec3A>, |
|
|
|
|
tex_v: std::vec::IntoIter<Vec3A>, |
|
|
|
|
nrm_v: std::vec::IntoIter<Vec3A>, |
|
|
|
|
pos_v: std::vec::IntoIter<Vec3>, |
|
|
|
|
tex_v: std::vec::IntoIter<Vec3>, |
|
|
|
|
nrm_v: std::vec::IntoIter<Vec3>, |
|
|
|
|
tan_v: std::vec::IntoIter<Vec4>, |
|
|
|
|
idx_v: std::vec::IntoIter<Vec4>, |
|
|
|
|
wgt_v: std::vec::IntoIter<Vec4>, |
|
|
|
|
clr_v: std::vec::IntoIter<Vec4>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct Mesh { |
|
|
|
|
mat: SmolStr, |
|
|
|
|
vtx: Range<usize>, |
|
|
|
|
idx: Range<usize>, |
|
|
|
|
struct Pose { |
|
|
|
|
par: usize, |
|
|
|
|
msk: u32, |
|
|
|
|
ofs: [f32; 10], |
|
|
|
|
scl: [f32; 10], |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct Joint { |
|
|
|
|
struct Joint { |
|
|
|
|
nam: SmolStr, |
|
|
|
|
mat: Mat4, |
|
|
|
|
inv: Mat4, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct Mesh { |
|
|
|
|
mat: SmolStr, |
|
|
|
|
vtx: Range<usize>, |
|
|
|
|
idx: Range<usize>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Data to be uploaded to the GPU. Separate from Model so that it may
|
|
|
|
|
/// be dropped after upload.
|
|
|
|
|
pub struct ModelData { |
|
|
|
@ -73,9 +82,9 @@ pub struct Model {
|
|
|
|
|
|
|
|
|
|
impl Iterator for VertexZipper { |
|
|
|
|
type Item = ( |
|
|
|
|
Option<Vec3A>, |
|
|
|
|
Option<Vec3A>, |
|
|
|
|
Option<Vec3A>, |
|
|
|
|
Option<Vec3>, |
|
|
|
|
Option<Vec3>, |
|
|
|
|
Option<Vec3>, |
|
|
|
|
Option<Vec4>, |
|
|
|
|
Option<Vec4>, |
|
|
|
|
Option<Vec4>, |
|
|
|
@ -109,49 +118,47 @@ const FMT_F64: u32 = 8;
|
|
|
|
|
|
|
|
|
|
fn fmt_check(fm: u32) -> Result<(), Err> { |
|
|
|
|
match fm { |
|
|
|
|
FMT_I8 | FMT_U8 | |
|
|
|
|
FMT_I16 | FMT_U16 | |
|
|
|
|
FMT_I32 | FMT_U32 | FMT_F32 | |
|
|
|
|
FMT_F64 => Ok(()), |
|
|
|
|
_ => Err(Err::VaFormat), |
|
|
|
|
| FMT_I8 | FMT_U8 | FMT_I16 | FMT_U16 | FMT_I32 | FMT_U32 | FMT_F32 |
|
|
|
|
| FMT_F64 => Ok(()), |
|
|
|
|
| _ => Err(Err::VaFormat), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn fmt_size(fm: u32) -> usize { |
|
|
|
|
match fm { |
|
|
|
|
FMT_I8 | FMT_U8 => 1, |
|
|
|
|
FMT_I16 | FMT_U16 => 2, |
|
|
|
|
FMT_I32 | FMT_U32 | FMT_F32 => 4, |
|
|
|
|
FMT_F64 => 8, |
|
|
|
|
_ => unsafe { std::hint::unreachable_unchecked() }, |
|
|
|
|
| FMT_I8 | FMT_U8 => 1, |
|
|
|
|
| FMT_I16 | FMT_U16 => 2, |
|
|
|
|
| FMT_I32 | FMT_U32 | FMT_F32 => 4, |
|
|
|
|
| FMT_F64 => 8, |
|
|
|
|
| _ => unsafe { std::hint::unreachable_unchecked() }, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn fmt_read_abs(fm: u32, vec: &[u8], pos: usize) -> f32 { |
|
|
|
|
match fm { |
|
|
|
|
FMT_I8 => f32::from(vec[pos] as i8), |
|
|
|
|
FMT_U8 => f32::from(vec[pos]), |
|
|
|
|
FMT_I16 => f32::from(read::i16le_16(vec, pos)), |
|
|
|
|
FMT_U16 => f32::from(read::u16le_16(vec, pos)), |
|
|
|
|
FMT_I32 => read::i32le_32(vec, pos) as f32, |
|
|
|
|
FMT_U32 => read::u32le_32(vec, pos) as f32, |
|
|
|
|
FMT_F32 => read::f32le_32(vec, pos), |
|
|
|
|
FMT_F64 => read::f64le_64(vec, pos) as f32, |
|
|
|
|
_ => unsafe { std::hint::unreachable_unchecked() }, |
|
|
|
|
| FMT_I8 => f32::from(vec[pos] as i8), |
|
|
|
|
| FMT_U8 => f32::from(vec[pos]), |
|
|
|
|
| FMT_I16 => f32::from(read::i16le_16(vec, pos)), |
|
|
|
|
| FMT_U16 => f32::from(read::u16le_16(vec, pos)), |
|
|
|
|
| FMT_I32 => read::i32le_32(vec, pos) as f32, |
|
|
|
|
| FMT_U32 => read::u32le_32(vec, pos) as f32, |
|
|
|
|
| FMT_F32 => read::f32le_32(vec, pos), |
|
|
|
|
| FMT_F64 => read::f64le_64(vec, pos) as f32, |
|
|
|
|
| _ => unsafe { std::hint::unreachable_unchecked() }, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn fmt_read_nrm(fm: u32, vec: &[u8], pos: usize) -> f32 { |
|
|
|
|
match fm { |
|
|
|
|
FMT_I8 => f32::abs(f32::from(vec[pos] as i8) / 128.0), |
|
|
|
|
FMT_U8 => f32::from(vec[pos]) / 255.0, |
|
|
|
|
FMT_I16 => f32::abs(f32::from(read::i16le_16(vec, pos)) / 32768.0), |
|
|
|
|
FMT_U16 => f32::from(read::u16le_16(vec, pos)) / 65535.0, |
|
|
|
|
FMT_I32 => (read::i32le_32(vec, pos) as f64 / 2147483648.0) as f32, |
|
|
|
|
FMT_U32 => (read::u32le_32(vec, pos) as f64 / 4294967295.0) as f32, |
|
|
|
|
FMT_F32 => f32::clamp(read::f32le_32(vec, pos), 0.0, 1.0), |
|
|
|
|
FMT_F64 => f32::clamp(read::f64le_64(vec, pos) as f32, 0.0, 1.0), |
|
|
|
|
_ => unsafe { std::hint::unreachable_unchecked() }, |
|
|
|
|
| FMT_I8 => f32::abs(f32::from(vec[pos] as i8) / 128.0), |
|
|
|
|
| FMT_U8 => f32::from(vec[pos]) / 255.0, |
|
|
|
|
| FMT_I16 => f32::abs(f32::from(read::i16le_16(vec, pos)) / 32768.0), |
|
|
|
|
| FMT_U16 => f32::from(read::u16le_16(vec, pos)) / 65535.0, |
|
|
|
|
| FMT_I32 => (read::i32le_32(vec, pos) as f64 / 2147483648.0) as f32, |
|
|
|
|
| FMT_U32 => (read::u32le_32(vec, pos) as f64 / 4294967295.0) as f32, |
|
|
|
|
| FMT_F32 => f32::clamp(read::f32le_32(vec, pos), 0.0, 1.0), |
|
|
|
|
| FMT_F64 => f32::clamp(read::f64le_64(vec, pos) as f32, 0.0, 1.0), |
|
|
|
|
| _ => unsafe { std::hint::unreachable_unchecked() }, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -254,20 +261,20 @@ impl Model {
|
|
|
|
|
|
|
|
|
|
let hunk = read::hunk(rd, obj_blks * num_vert)?; |
|
|
|
|
|
|
|
|
|
let v2 = |v: &mut Vec<Vec3A>, rd: fn(u32, &[u8], usize) -> f32| { |
|
|
|
|
let v2 = |v: &mut Vec<Vec3>, rd: fn(u32, &[u8], usize) -> f32| { |
|
|
|
|
if obj_amnt != 2 { |
|
|
|
|
Err(Err::VaFormat) |
|
|
|
|
} else { |
|
|
|
|
for vec in hunk.chunks(obj_blks) { |
|
|
|
|
let x = rd(fm, vec, obj_size * 0); |
|
|
|
|
let y = rd(fm, vec, obj_size * 1); |
|
|
|
|
v.push(Vec3A::new(x, y, 0.0)); |
|
|
|
|
v.push(Vec3::new(x, y, 0.0)); |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let v3 = |v: &mut Vec<Vec3A>, rd: fn(u32, &[u8], usize) -> f32| { |
|
|
|
|
let v3 = |v: &mut Vec<Vec3>, rd: fn(u32, &[u8], usize) -> f32| { |
|
|
|
|
if obj_amnt != 3 { |
|
|
|
|
Err(Err::VaFormat) |
|
|
|
|
} else { |
|
|
|
@ -275,7 +282,7 @@ impl Model {
|
|
|
|
|
let x = rd(fm, vec, obj_size * 0); |
|
|
|
|
let y = rd(fm, vec, obj_size * 1); |
|
|
|
|
let z = rd(fm, vec, obj_size * 2); |
|
|
|
|
v.push(Vec3A::new(x, y, z)); |
|
|
|
|
v.push(Vec3::new(x, y, z)); |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
@ -322,9 +329,9 @@ impl Model {
|
|
|
|
|
let mut vert_dat = Vec::with_capacity(num_vert); |
|
|
|
|
|
|
|
|
|
for (pos, tex, nrm, tan, idx, wgt, clr) in zipper { |
|
|
|
|
let pos = pos.unwrap_or_else(|| Vec3A::ZERO); |
|
|
|
|
let tex = tex.unwrap_or_else(|| Vec3A::ZERO); |
|
|
|
|
let nrm = nrm.unwrap_or_else(|| Vec3A::ZERO); |
|
|
|
|
let pos = pos.unwrap_or_else(|| Vec3::ZERO); |
|
|
|
|
let tex = tex.unwrap_or_else(|| Vec3::ZERO); |
|
|
|
|
let nrm = nrm.unwrap_or_else(|| Vec3::ZERO); |
|
|
|
|
let tan = tan.unwrap_or_else(|| Vec4::ZERO); |
|
|
|
|
let idx = idx.unwrap_or_else(|| Vec4::ZERO); |
|
|
|
|
let wgt = wgt.unwrap_or_else(|| Vec4::ZERO); |
|
|
|
@ -383,11 +390,11 @@ impl Model {
|
|
|
|
|
|
|
|
|
|
let nam = SmolStr::new(from_stab(&stab, nam)?); |
|
|
|
|
|
|
|
|
|
let mut mat = Mat4::from_scale_rotation_translation( |
|
|
|
|
Vec3::new(trs[7], trs[8], trs[9]), |
|
|
|
|
Quat::from_xyzw(trs[3], trs[4], trs[5], trs[6]).normalize(), |
|
|
|
|
Vec3::new(trs[0], trs[1], trs[2]), |
|
|
|
|
); |
|
|
|
|
let xlt = Vec3::new(trs[0], trs[1], trs[2]); |
|
|
|
|
let rot = Quat::from_xyzw(trs[3], trs[4], trs[5], trs[6]).normalize(); |
|
|
|
|
let scl = Vec3::new(trs[7], trs[8], trs[9]); |
|
|
|
|
|
|
|
|
|
let mut mat = Mat4::from_scale_rotation_translation(scl, rot, xlt); |
|
|
|
|
let mut inv = mat.inverse(); |
|
|
|
|
|
|
|
|
|
if par & 0x8000_0000 == 0 { |
|
|
|
@ -409,59 +416,70 @@ impl Model {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// collect pose info
|
|
|
|
|
let mut frame = frames.iter(); |
|
|
|
|
let mut frames = Vec::with_capacity(num_pose); |
|
|
|
|
let mut poses = Vec::with_capacity(num_pose); |
|
|
|
|
|
|
|
|
|
rd.seek(SeekFrom::Start(ofs_pose))?; |
|
|
|
|
|
|
|
|
|
for (pose, pose_n) in |
|
|
|
|
read::hunk(rd, num_pose * 4 * 22)?.chunks(4 * 22).zip(0..num_pose) |
|
|
|
|
{ |
|
|
|
|
for pose in read::hunk(rd, num_pose * 4 * 22)?.chunks(4 * 22) { |
|
|
|
|
let par = read::u32le_sz(pose, 0); |
|
|
|
|
let msk = read::u32le_32(pose, 4); |
|
|
|
|
|
|
|
|
|
let mut ofs = [0.0; 10]; |
|
|
|
|
let mut scl = [0.0; 10]; |
|
|
|
|
read::array(read::f32le_32, pose, &mut ofs, 4, 8); |
|
|
|
|
read::array(read::f32le_32, pose, &mut scl, 4, 48); |
|
|
|
|
|
|
|
|
|
let mut pose_mats = Vec::with_capacity(num_frms); |
|
|
|
|
poses.push(Pose { par, msk, ofs, scl }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _frame_num in 0..num_frms { |
|
|
|
|
let mut ofs = ofs; |
|
|
|
|
// calculate frame matrices
|
|
|
|
|
let mut frame = frames.iter(); |
|
|
|
|
let mut frames = Vec::with_capacity(num_frms); |
|
|
|
|
|
|
|
|
|
for _ in 0..num_frms { |
|
|
|
|
let mut frame_mats = Vec::with_capacity(num_pose); |
|
|
|
|
|
|
|
|
|
for (pose, joint) in poses.iter().zip(joints.iter()) { |
|
|
|
|
let mut ofs = pose.ofs; |
|
|
|
|
|
|
|
|
|
for i in 0..10 { |
|
|
|
|
if msk & 1 << i != 0 { |
|
|
|
|
ofs[i] += |
|
|
|
|
f32::from(*frame.next().ok_or(Err::FrameCount)?) * scl[i]; |
|
|
|
|
if pose.msk & 1 << i != 0 { |
|
|
|
|
let frm = f32::from(*frame.next().ok_or(Err::FrameCount)?); |
|
|
|
|
ofs[i] += frm * pose.scl[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let mut mat = Mat4::from_scale_rotation_translation( |
|
|
|
|
Vec3::new(ofs[7], ofs[8], ofs[9]), |
|
|
|
|
Quat::from_xyzw(ofs[3], ofs[4], ofs[5], ofs[6]).normalize(), |
|
|
|
|
Vec3::new(ofs[0], ofs[1], ofs[2]), |
|
|
|
|
); |
|
|
|
|
let xlt = Vec3::new(ofs[0], ofs[1], ofs[2]); |
|
|
|
|
let rot = |
|
|
|
|
Quat::from_xyzw(ofs[3], ofs[4], ofs[5], ofs[6]).normalize(); |
|
|
|
|
let scl = Vec3::new(ofs[7], ofs[8], ofs[9]); |
|
|
|
|
|
|
|
|
|
let joint = &joints[pose_n]; |
|
|
|
|
let mut mat = Mat4::from_scale_rotation_translation(scl, rot, xlt); |
|
|
|
|
|
|
|
|
|
if par & 0x8000_0000 == 0 { |
|
|
|
|
let parent = joints.get(par).ok_or(Err::Parent)?; |
|
|
|
|
if pose.par & 0x8000_0000 == 0 { |
|
|
|
|
let parent = joints.get(pose.par).ok_or(Err::Parent)?; |
|
|
|
|
mat = parent.mat * mat * joint.inv; |
|
|
|
|
|
|
|
|
|
let parent = frame_mats.get(pose.par).ok_or(Err::Parent)?; |
|
|
|
|
mat = *parent * mat; |
|
|
|
|
} else { |
|
|
|
|
mat = mat * joint.inv; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pose_mats.push(mat); |
|
|
|
|
frame_mats.push(mat); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
frames.push(pose_mats); |
|
|
|
|
frames.push(frame_mats); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok((Self { meshes, frames, num_frms }, ModelData { vtx: vert_dat, idx: indx_dat })) |
|
|
|
|
Ok(( |
|
|
|
|
Self { meshes, frames, num_frms }, |
|
|
|
|
ModelData { vtx: vert_dat, idx: indx_dat }, |
|
|
|
|
)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn frame(&self, joint: usize, frame: usize) -> Option<Mat4> { |
|
|
|
|
Some(*self.frames.get(joint)?.get(frame)?) |
|
|
|
|
Some(*self.frames.get(frame)?.get(joint)?) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub const fn num_frames(&self) -> usize { |
|
|
|
|