|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|
|
|
|
data::{read, vertex::Vertex}, |
|
|
|
|
ffi, |
|
|
|
|
math::*, |
|
|
|
|
types::StkStr, |
|
|
|
|
types::{Cast, StkStr}, |
|
|
|
|
}; |
|
|
|
|
use std::{ |
|
|
|
|
collections::HashMap, |
|
|
|
@ -11,7 +11,8 @@ use std::{
|
|
|
|
|
str::Utf8Error, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#[derive(Error, Debug)] |
|
|
|
|
#[derive(thiserror::Error, Debug)] |
|
|
|
|
#[non_exhaustive] |
|
|
|
|
pub enum Err { |
|
|
|
|
#[error(transparent)] |
|
|
|
|
Io(#[from] io::Error), |
|
|
|
@ -41,6 +42,7 @@ struct Pose {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct Joint { |
|
|
|
|
#[allow(dead_code)] |
|
|
|
|
nam: StkStr, |
|
|
|
|
mat: Mat4, |
|
|
|
|
inv: Mat4, |
|
|
|
@ -77,7 +79,7 @@ const FMT_F16: u32 = 6;
|
|
|
|
|
const FMT_F32: u32 = 7; |
|
|
|
|
const FMT_F64: u32 = 8; |
|
|
|
|
|
|
|
|
|
fn fmt_check(fm: u32) -> Result<(), Err> { |
|
|
|
|
const fn fmt_check(fm: u32) -> Result<(), Err> { |
|
|
|
|
match fm { |
|
|
|
|
| FMT_I8 | FMT_U8 | FMT_I16 | FMT_U16 | FMT_I32 | FMT_U32 | FMT_F16 |
|
|
|
|
| FMT_F32 | FMT_F64 => Ok(()), |
|
|
|
@ -97,30 +99,30 @@ fn fmt_size(fm: u32) -> usize {
|
|
|
|
|
|
|
|
|
|
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_F16 => read::f16le_32(vec, pos), |
|
|
|
|
| FMT_F32 => read::f32le_32(vec, pos), |
|
|
|
|
| FMT_F64 => read::f64le_32(vec, pos), |
|
|
|
|
| FMT_I8 => read::i8x(vec, pos).into(), |
|
|
|
|
| FMT_U8 => read::u8x(vec, pos).into(), |
|
|
|
|
| FMT_I16 => read::i16le(vec, pos).into(), |
|
|
|
|
| FMT_U16 => read::u16le(vec, pos).into(), |
|
|
|
|
| FMT_I32 => read::i32le(vec, pos).cast(), |
|
|
|
|
| FMT_U32 => read::u32le(vec, pos).cast(), |
|
|
|
|
| FMT_F16 => read::f16le(vec, pos).to_f32(), |
|
|
|
|
| FMT_F32 => read::f32le(vec, pos), |
|
|
|
|
| FMT_F64 => read::f64le(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_F16 => f32::clamp(read::f16le_32(vec, pos), 0.0, 1.0), |
|
|
|
|
| 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), |
|
|
|
|
| FMT_I8 => f32::from(read::i8x(vec, pos)).abs() / 128.0, |
|
|
|
|
| FMT_U8 => f32::from(read::u8x(vec, pos)) / 255.0, |
|
|
|
|
| FMT_I16 => f32::from(read::i16le(vec, pos)).abs() / 32768.0, |
|
|
|
|
| FMT_U16 => f32::from(read::u16le(vec, pos)) / 65535.0, |
|
|
|
|
| FMT_I32 => (f64::from(read::i32le(vec, pos)) / 2147483648.0) as f32, |
|
|
|
|
| FMT_U32 => (f64::from(read::u32le(vec, pos)) / 4294967295.0) as f32, |
|
|
|
|
| FMT_F16 => f32::clamp(read::f16le(vec, pos).to_f32(), 0.0, 1.0), |
|
|
|
|
| FMT_F32 => f32::clamp(read::f32le(vec, pos), 0.0, 1.0), |
|
|
|
|
| FMT_F64 => f32::clamp(read::f64le(vec, pos) as f32, 0.0, 1.0), |
|
|
|
|
| _ => unsafe { std::hint::unreachable_unchecked() }, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -172,25 +174,25 @@ impl Model {
|
|
|
|
|
return Err(Err::Magic); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let num_text = read::u32le_sz(&head, 28); |
|
|
|
|
let ofs_text = read::u32le_64(&head, 32); |
|
|
|
|
let num_mesh = read::u32le_sz(&head, 36); |
|
|
|
|
let ofs_mesh = read::u32le_64(&head, 40); |
|
|
|
|
let num_vinf = read::u32le_sz(&head, 44); |
|
|
|
|
let num_vert = read::u32le_sz(&head, 48); |
|
|
|
|
let ofs_vinf = read::u32le_64(&head, 52); |
|
|
|
|
let num_tris = read::u32le_sz(&head, 56); |
|
|
|
|
let ofs_tris = read::u32le_64(&head, 60); |
|
|
|
|
let num_join = read::u32le_sz(&head, 68); |
|
|
|
|
let ofs_join = read::u32le_64(&head, 72); |
|
|
|
|
let num_pose = read::u32le_sz(&head, 76); |
|
|
|
|
let ofs_pose = read::u32le_64(&head, 80); |
|
|
|
|
let num_anim = read::u32le_sz(&head, 84); |
|
|
|
|
let ofs_anim = read::u32le_64(&head, 88); |
|
|
|
|
let num_frms = read::u32le_sz(&head, 92); |
|
|
|
|
let num_frmc = read::u32le_sz(&head, 96); |
|
|
|
|
let ofs_frms = read::u32le_64(&head, 100); |
|
|
|
|
let ofs_bnds = read::u32le_64(&head, 104); |
|
|
|
|
let num_text = read::u32le(&head, 28) as usize; |
|
|
|
|
let ofs_text = read::u32le(&head, 32).into(); |
|
|
|
|
let num_mesh = read::u32le(&head, 36) as usize; |
|
|
|
|
let ofs_mesh = read::u32le(&head, 40).into(); |
|
|
|
|
let num_vinf = read::u32le(&head, 44) as usize; |
|
|
|
|
let num_vert = read::u32le(&head, 48) as usize; |
|
|
|
|
let ofs_vinf = read::u32le(&head, 52).into(); |
|
|
|
|
let num_tris = read::u32le(&head, 56) as usize; |
|
|
|
|
let ofs_tris = read::u32le(&head, 60).into(); |
|
|
|
|
let num_join = read::u32le(&head, 68) as usize; |
|
|
|
|
let ofs_join = read::u32le(&head, 72).into(); |
|
|
|
|
let num_pose = read::u32le(&head, 76) as usize; |
|
|
|
|
let ofs_pose = read::u32le(&head, 80).into(); |
|
|
|
|
//let num_anim = read::u32le(&head, 84) as usize;
|
|
|
|
|
//let ofs_anim = read::u32le(&head, 88).into();
|
|
|
|
|
let num_frms = read::u32le(&head, 92) as usize; |
|
|
|
|
let num_frmc = read::u32le(&head, 96) as usize; |
|
|
|
|
let ofs_frms = read::u32le(&head, 100).into(); |
|
|
|
|
//let ofs_bnds = read::u32le(&head, 104).into();
|
|
|
|
|
|
|
|
|
|
if num_join != 0 && num_pose != 0 && num_pose != num_join { |
|
|
|
|
return Err(Err::NumPoses); |
|
|
|
@ -208,29 +210,28 @@ impl Model {
|
|
|
|
|
rd.seek(SeekFrom::Start(ofs_vinf))?; |
|
|
|
|
|
|
|
|
|
for array_def in read::hunk(rd, num_vinf * 20)?.chunks(20) { |
|
|
|
|
let ty = read::u32le_32(array_def, 0); |
|
|
|
|
let fl = read::u32le_32(array_def, 4); |
|
|
|
|
let fm = read::u32le_32(array_def, 8); |
|
|
|
|
let sz = read::u32le_32(array_def, 12); |
|
|
|
|
let of = read::u32le_64(array_def, 16); |
|
|
|
|
let ty = read::u32le(array_def, 0); |
|
|
|
|
//let fl = read::u32le(array_def, 4);
|
|
|
|
|
let fm = read::u32le(array_def, 8); |
|
|
|
|
let sz = read::u32le(array_def, 12) as usize; |
|
|
|
|
let of = read::u32le(array_def, 16).into(); |
|
|
|
|
|
|
|
|
|
fmt_check(fm)?; |
|
|
|
|
|
|
|
|
|
rd.seek(SeekFrom::Start(of))?; |
|
|
|
|
|
|
|
|
|
let obj_size = fmt_size(fm); |
|
|
|
|
let obj_amnt = sz as usize; |
|
|
|
|
let obj_blks = obj_size * obj_amnt; |
|
|
|
|
let obj_blks = obj_size * sz; |
|
|
|
|
|
|
|
|
|
let hunk = read::hunk(rd, obj_blks * num_vert)?; |
|
|
|
|
|
|
|
|
|
let v2 = |v: &mut Vec<Vec3>, rd: fn(u32, &[u8], usize) -> f32| { |
|
|
|
|
if obj_amnt != 2 { |
|
|
|
|
if sz != 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); |
|
|
|
|
let x = rd(fm, vec, 0); |
|
|
|
|
let y = rd(fm, vec, obj_size); |
|
|
|
|
v.push(Vec3::new(x, y, 0.0)); |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
@ -238,12 +239,12 @@ impl Model {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let v3 = |v: &mut Vec<Vec3>, rd: fn(u32, &[u8], usize) -> f32| { |
|
|
|
|
if obj_amnt != 3 { |
|
|
|
|
if sz != 3 { |
|
|
|
|
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); |
|
|
|
|
let x = rd(fm, vec, 0); |
|
|
|
|
let y = rd(fm, vec, obj_size); |
|
|
|
|
let z = rd(fm, vec, obj_size * 2); |
|
|
|
|
v.push(Vec3::new(x, y, z)); |
|
|
|
|
} |
|
|
|
@ -252,12 +253,12 @@ impl Model {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let v4 = |v: &mut Vec<Vec4>, rd: fn(u32, &[u8], usize) -> f32| { |
|
|
|
|
if obj_amnt != 4 { |
|
|
|
|
if sz != 4 { |
|
|
|
|
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); |
|
|
|
|
let x = rd(fm, vec, 0); |
|
|
|
|
let y = rd(fm, vec, obj_size); |
|
|
|
|
let z = rd(fm, vec, obj_size * 2); |
|
|
|
|
let w = rd(fm, vec, obj_size * 3); |
|
|
|
|
v.push(Vec4::new(x, y, z, w)); |
|
|
|
@ -290,14 +291,15 @@ impl Model {
|
|
|
|
|
wgt_v.into_iter(), |
|
|
|
|
clr_v.into_iter(), |
|
|
|
|
)) { |
|
|
|
|
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); |
|
|
|
|
let clr = clr.unwrap_or_else(|| Vec4::ONE); |
|
|
|
|
vert_dat.push(Vertex { pos, tex, nrm, tan, idx, wgt, clr }); |
|
|
|
|
vert_dat.push(Vertex { |
|
|
|
|
pos: pos.unwrap_or(Vec3::ZERO), |
|
|
|
|
tex: tex.unwrap_or(Vec3::ZERO), |
|
|
|
|
nrm: nrm.unwrap_or(Vec3::ZERO), |
|
|
|
|
tan: tan.unwrap_or(Vec4::ZERO), |
|
|
|
|
idx: idx.unwrap_or(Vec4::ZERO), |
|
|
|
|
wgt: wgt.unwrap_or(Vec4::ZERO), |
|
|
|
|
clr: clr.unwrap_or(Vec4::ONE), |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// collect index info
|
|
|
|
@ -306,9 +308,9 @@ impl Model {
|
|
|
|
|
rd.seek(SeekFrom::Start(ofs_tris))?; |
|
|
|
|
|
|
|
|
|
for tri in read::hunk(rd, num_tris * 4 * 3)?.chunks(4 * 3) { |
|
|
|
|
indx_dat.push(read::u32le_32(tri, 0)); |
|
|
|
|
indx_dat.push(read::u32le_32(tri, 4)); |
|
|
|
|
indx_dat.push(read::u32le_32(tri, 8)); |
|
|
|
|
indx_dat.push(read::u32le(tri, 0)); |
|
|
|
|
indx_dat.push(read::u32le(tri, 4)); |
|
|
|
|
indx_dat.push(read::u32le(tri, 8)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// collect text
|
|
|
|
@ -322,12 +324,12 @@ impl Model {
|
|
|
|
|
rd.seek(SeekFrom::Start(ofs_mesh))?; |
|
|
|
|
|
|
|
|
|
for mesh in read::hunk(rd, num_mesh * 4 * 6)?.chunks(4 * 6) { |
|
|
|
|
let nam = read::u32le_sz(mesh, 0); |
|
|
|
|
let mat = read::u32le_sz(mesh, 4); |
|
|
|
|
let vtx = read::u32le_sz(mesh, 8); |
|
|
|
|
let vnu = read::u32le_sz(mesh, 12); |
|
|
|
|
let idx = read::u32le_sz(mesh, 16) * 3; |
|
|
|
|
let inu = read::u32le_sz(mesh, 20) * 3; |
|
|
|
|
let nam = read::u32le(mesh, 0) as usize; |
|
|
|
|
let mat = read::u32le(mesh, 4) as usize; |
|
|
|
|
let vtx = read::u32le(mesh, 8) as usize; |
|
|
|
|
let vnu = read::u32le(mesh, 12) as usize; |
|
|
|
|
let idx = read::u32le(mesh, 16) as usize * 3; |
|
|
|
|
let inu = read::u32le(mesh, 20) as usize * 3; |
|
|
|
|
|
|
|
|
|
let nam = StkStr::new(from_stab(&stab, nam)?); |
|
|
|
|
let mat = StkStr::new(from_stab(&stab, mat)?); |
|
|
|
@ -344,9 +346,9 @@ impl Model {
|
|
|
|
|
rd.seek(SeekFrom::Start(ofs_join))?; |
|
|
|
|
|
|
|
|
|
for join in read::hunk(rd, num_join * 4 * 12)?.chunks(4 * 12) { |
|
|
|
|
let nam = read::u32le_sz(join, 0); |
|
|
|
|
let par = read::u32le_sz(join, 4); |
|
|
|
|
let trs = read::array(read::f32le_32, join, [0.0; 10], 4, 8); |
|
|
|
|
let nam = read::u32le(join, 0) as usize; |
|
|
|
|
let par = read::u32le(join, 4) as usize; |
|
|
|
|
let trs = read::array(read::f32le, join, [0.0; 10], 4, 8); |
|
|
|
|
|
|
|
|
|
let nam = StkStr::new(from_stab(&stab, nam)?); |
|
|
|
|
|
|
|
|
@ -372,7 +374,7 @@ impl Model {
|
|
|
|
|
rd.seek(SeekFrom::Start(ofs_frms))?; |
|
|
|
|
|
|
|
|
|
for samp in read::hunk(rd, num_frms * num_frmc * 2)?.chunks(2) { |
|
|
|
|
frames.push(read::u16le_16(samp, 0)); |
|
|
|
|
frames.push(read::u16le(samp, 0)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// collect pose info
|
|
|
|
@ -381,10 +383,10 @@ impl Model {
|
|
|
|
|
rd.seek(SeekFrom::Start(ofs_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 ofs = read::array(read::f32le_32, pose, [0.0; 10], 4, 8); |
|
|
|
|
let scl = read::array(read::f32le_32, pose, [0.0; 10], 4, 48); |
|
|
|
|
let par = read::u32le(pose, 0) as usize; |
|
|
|
|
let msk = read::u32le(pose, 4); |
|
|
|
|
let ofs = read::array(read::f32le, pose, [0.0; 10], 4, 8); |
|
|
|
|
let scl = read::array(read::f32le, pose, [0.0; 10], 4, 48); |
|
|
|
|
|
|
|
|
|
poses.push(Pose { par, msk, ofs, scl }); |
|
|
|
|
} |
|
|
|
@ -399,10 +401,10 @@ impl Model {
|
|
|
|
|
for (pose, joint) in poses.iter().zip(joints.iter()) { |
|
|
|
|
let mut ofs = pose.ofs; |
|
|
|
|
|
|
|
|
|
for i in 0..10 { |
|
|
|
|
for (i, off) in ofs.iter_mut().enumerate() { |
|
|
|
|
if pose.msk & 1 << i != 0 { |
|
|
|
|
let frm = f32::from(*frame.next().ok_or(Err::FrameCount)?); |
|
|
|
|
ofs[i] += frm * pose.scl[i]; |
|
|
|
|
*off += frm * pose.scl[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|