mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
finaly got orientation figured out I think
This commit is contained in:
parent
06cbe395eb
commit
2dffd8d7cd
9 changed files with 171 additions and 75 deletions
|
|
@ -1,11 +1,11 @@
|
||||||
use cgmath::Euler;
|
use cgmath::{Euler, Matrix4};
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use vmdl::mdl::Mdl;
|
use vmdl::mdl::Mdl;
|
||||||
use vmdl::vtx::Vtx;
|
use vmdl::vtx::Vtx;
|
||||||
use vmdl::vvd::Vvd;
|
use vmdl::vvd::Vvd;
|
||||||
use vmdl::Model;
|
use vmdl::{Model, Quaternion};
|
||||||
|
|
||||||
fn main() -> Result<(), vmdl::ModelError> {
|
fn main() -> Result<(), vmdl::ModelError> {
|
||||||
let mut args = args();
|
let mut args = args();
|
||||||
|
|
@ -19,25 +19,33 @@ fn main() -> Result<(), vmdl::ModelError> {
|
||||||
let data = fs::read(path.with_extension("vvd"))?;
|
let data = fs::read(path.with_extension("vvd"))?;
|
||||||
let vvd = Vvd::read(&data)?;
|
let vvd = Vvd::read(&data)?;
|
||||||
|
|
||||||
// dbg!(&mdl.header2);
|
// dbg!(&mdl.header);
|
||||||
|
|
||||||
// for bone in &mdl.bones {
|
// for bone in &mdl.bones {
|
||||||
// println!(
|
// println!(
|
||||||
// "{}: from {} at\n\t{:?}\n\t{:?}\n\t{:?}",
|
// "{}: from {} at\n\t{:?}\n\t{:?}\n\t{:?}\n\t{:?}",
|
||||||
// bone.name, bone.parent, bone.rot, bone.q_alignment, bone.pose_to_bone
|
// bone.name, bone.parent, bone.rot, bone.rot_scale, bone.quaternion, bone.pose_to_bone
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
dbg!(&mdl.local_animations[0]);
|
// dbg!(&mdl.bones[0]);
|
||||||
|
dbg!(&mdl.local_animations[0].animations[0]);
|
||||||
let transform = mdl
|
let transform = mdl
|
||||||
.local_animations
|
.local_animations
|
||||||
.first()
|
.get(0)
|
||||||
.map(|a| a.animations[0].rotation(0))
|
.map(|a| a.animations[0].rotation(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
dbg!(transform);
|
dbg!(transform);
|
||||||
dbg!(Euler::from(cgmath::Quaternion::from(transform)));
|
dbg!(Euler::from(cgmath::Quaternion::from(transform)));
|
||||||
|
// dbg!(&mdl.body_table_by_name);
|
||||||
|
|
||||||
// dbg!(&mdl.attachments);
|
// dbg!(&mdl.attachments);
|
||||||
let _model = Model::from_parts(mdl, vtx, vvd);
|
let model = Model::from_parts(mdl, vtx, vvd);
|
||||||
|
dbg!(model.animations().nth(1).unwrap().get_bone_transform(1, 0));
|
||||||
|
// dbg!(model.root_transform());
|
||||||
|
// dbg!(model.idle_transform());
|
||||||
|
// dbg!(Euler::from(cgmath::Quaternion::from(
|
||||||
|
// model.idle_transform()
|
||||||
|
// )));
|
||||||
// dbg!(Euler::from(Quaternion::from(model.root_transform())));
|
// dbg!(Euler::from(Quaternion::from(model.root_transform())));
|
||||||
// for strip in model.vertex_strips() {
|
// for strip in model.vertex_strips() {
|
||||||
// for vertex in strip {
|
// for vertex in strip {
|
||||||
|
|
|
||||||
|
|
@ -250,9 +250,7 @@ fn model_to_model(model: &Model, loader: &Loader, skin: usize) -> CpuModel {
|
||||||
|
|
||||||
let skin = model.skin_tables().nth(skin).unwrap();
|
let skin = model.skin_tables().nth(skin).unwrap();
|
||||||
|
|
||||||
let transforms = model.root_transform();
|
let transforms = Matrix4::identity();
|
||||||
let transforms = dbg!(model.idle_transform());
|
|
||||||
// let transforms = Matrix4::identity();
|
|
||||||
|
|
||||||
let geometries = model
|
let geometries = model
|
||||||
.meshes()
|
.meshes()
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,21 @@ pub struct Quaternion48 {
|
||||||
z: u16,
|
z: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Quaternion48 {
|
||||||
|
fn default() -> Self {
|
||||||
|
Quaternion48 {
|
||||||
|
x: 32768,
|
||||||
|
y: 32768,
|
||||||
|
z: 16384,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ReadableRelative for Quaternion48 {}
|
impl ReadableRelative for Quaternion48 {}
|
||||||
|
|
||||||
fn calc_w(x: f32, y: f32, z: f32, w_neg: bool) -> f32 {
|
fn calc_w(x: f32, y: f32, z: f32, w_neg: bool) -> f32 {
|
||||||
let w_sign = if w_neg { -1.0 } else { 1.0 };
|
let w_sign = if w_neg { -1.0 } else { 1.0 };
|
||||||
f32::sqrt(1.0 - ((x * x) - (y * y) - (z * z))) * w_sign
|
f32::sqrt(1.0 - (x * x) - (y * y) - (z * z)) * w_sign
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Quaternion48 {
|
impl Quaternion48 {
|
||||||
|
|
@ -92,14 +102,13 @@ pub struct Quaternion64(u64);
|
||||||
impl ReadableRelative for Quaternion64 {}
|
impl ReadableRelative for Quaternion64 {}
|
||||||
|
|
||||||
impl Quaternion64 {
|
impl Quaternion64 {
|
||||||
const MASK_21_BIT: u64 = 0b111111111111111111111;
|
const MASK_21_BIT: u64 = 0b11111_11111111_11111111;
|
||||||
const W_NEG_MASK: u64 = 0x80_00_00_00_00_00_00_00;
|
const W_NEG_MASK: u64 = 0x80_00_00_00_00_00_00_00;
|
||||||
|
|
||||||
fn val(&self, offset: i32) -> f32 {
|
fn val(&self, offset: i32) -> f32 {
|
||||||
let raw = (self.0 >> offset) & Self::MASK_21_BIT;
|
let raw = ((self.0) >> offset) & Self::MASK_21_BIT;
|
||||||
(raw as f32 - 1048576.0) / 1048576.5
|
(raw as f32 - 1048576.0) / 1048576.5
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn x(&self) -> f32 {
|
pub fn x(&self) -> f32 {
|
||||||
self.val(0)
|
self.val(0)
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +130,7 @@ impl Quaternion64 {
|
||||||
|
|
||||||
impl From<Quaternion64> for Quaternion {
|
impl From<Quaternion64> for Quaternion {
|
||||||
fn from(value: Quaternion64) -> Self {
|
fn from(value: Quaternion64) -> Self {
|
||||||
let normalized = Vector4::new(value.x(), value.y(), value.z(), value.w()).normalize();
|
let normalized = Vector4::new(value.x(), value.y(), value.z(), value.w());
|
||||||
Quaternion {
|
Quaternion {
|
||||||
x: normalized.x,
|
x: normalized.x,
|
||||||
y: normalized.y,
|
y: normalized.y,
|
||||||
|
|
|
||||||
56
src/lib.rs
56
src/lib.rs
|
|
@ -7,12 +7,12 @@ pub mod vtx;
|
||||||
pub mod vvd;
|
pub mod vvd;
|
||||||
|
|
||||||
pub use crate::mdl::Mdl;
|
pub use crate::mdl::Mdl;
|
||||||
use crate::mdl::{Bone, ModelFlags, PoseParameterDescription, TextureInfo};
|
use crate::mdl::{AnimationDescription, Bone, ModelFlags, PoseParameterDescription, TextureInfo};
|
||||||
pub use crate::vtx::Vtx;
|
pub use crate::vtx::Vtx;
|
||||||
use crate::vvd::Vertex;
|
use crate::vvd::Vertex;
|
||||||
pub use crate::vvd::Vvd;
|
pub use crate::vvd::Vvd;
|
||||||
use bytemuck::{pod_read_unaligned, Contiguous, Pod};
|
use bytemuck::{pod_read_unaligned, Contiguous, Pod};
|
||||||
use cgmath::{Matrix4, SquareMatrix};
|
use cgmath::{Matrix4, SquareMatrix, Transform, Vector3};
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use handle::Handle;
|
pub use handle::Handle;
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
|
|
@ -85,6 +85,10 @@ impl Model {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn animations(&self) -> impl Iterator<Item = &AnimationDescription> {
|
||||||
|
self.mdl.local_animations.iter()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn meshes(&self) -> impl Iterator<Item = Mesh> {
|
pub fn meshes(&self) -> impl Iterator<Item = Mesh> {
|
||||||
let mdl_meshes = self
|
let mdl_meshes = self
|
||||||
.mdl
|
.mdl
|
||||||
|
|
@ -140,9 +144,13 @@ impl Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.bones()
|
self.bones()
|
||||||
.find(|bone| bone.name != "root")
|
.next()
|
||||||
.map(|bone| bone.pose_to_bone)
|
.map(|bone| {
|
||||||
.map(Matrix4::from)
|
// let inv = Matrix4::from(bone.pose_to_bone)
|
||||||
|
// .inverse_transform()
|
||||||
|
// .unwrap();
|
||||||
|
Matrix4::from(bone.rot)
|
||||||
|
})
|
||||||
.unwrap_or_else(Matrix4::identity)
|
.unwrap_or_else(Matrix4::identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,8 +161,9 @@ impl Model {
|
||||||
|
|
||||||
self.mdl
|
self.mdl
|
||||||
.local_animations
|
.local_animations
|
||||||
.first()
|
.iter()
|
||||||
.and_then(|desc| desc.animations.first())
|
.filter_map(|desc| desc.animations.iter().find(|animation| animation.bone == 0))
|
||||||
|
.find(|anim| anim.rotation_looks_valid())
|
||||||
.map(|animation| animation.rotation(0))
|
.map(|animation| animation.rotation(0))
|
||||||
.map(Matrix4::from)
|
.map(Matrix4::from)
|
||||||
.unwrap_or_else(Matrix4::identity)
|
.unwrap_or_else(Matrix4::identity)
|
||||||
|
|
@ -169,24 +178,23 @@ impl Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vertex_to_world_space(&self, vertex: &Vertex) -> Vector {
|
pub fn vertex_to_world_space(&self, vertex: &Vertex) -> Vector {
|
||||||
// vertex.position.transformed(self.root_transform())
|
let transform = self.idle_transform() * self.root_transform();
|
||||||
vertex.position.transformed(self.idle_transform())
|
transform
|
||||||
|
.transform_vector(Vector3::from(vertex.position))
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
// let mut pos = Vector3::from(vertex.position);
|
fn bone_transform(
|
||||||
// for weights in vertex.bone_weights.weights() {
|
&self,
|
||||||
// if let Some(bone) = self.mdl.bones.get(weights.bone_id as usize) {
|
bone_id: u8,
|
||||||
// let transform = Quaternion::from(bone.rot);
|
bone: &Bone,
|
||||||
// if bone.parent == 0 {
|
animation: &AnimationDescription,
|
||||||
// if bone.name == "joint1" {
|
weight: f32,
|
||||||
// dbg!(&bone.name, bone.rot, transform);
|
frame: usize,
|
||||||
// }
|
) -> Matrix4<f32> {
|
||||||
// let transform = Matrix4::from(transform);
|
let animation_transform = weight * animation.get_bone_transform(bone_id, frame);
|
||||||
// pos = transform.transform_vector(pos);
|
let bone_origin = Matrix4::from(bone.pose_to_bone);
|
||||||
// // pos = bone.pose_to_bone.transform(pos);
|
bone_origin.inverse_transform().unwrap() * animation_transform * bone_origin
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// pos.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ pub struct Mdl {
|
||||||
pub header2: Option<StudioHeader2>,
|
pub header2: Option<StudioHeader2>,
|
||||||
pub bones: Vec<Bone>,
|
pub bones: Vec<Bone>,
|
||||||
pub bone_controllers: Vec<BoneController>,
|
pub bone_controllers: Vec<BoneController>,
|
||||||
|
pub body_table_by_name: Vec<u8>,
|
||||||
pub body_parts: Vec<BodyPart>,
|
pub body_parts: Vec<BodyPart>,
|
||||||
pub textures: Vec<TextureInfo>,
|
pub textures: Vec<TextureInfo>,
|
||||||
pub texture_paths: Vec<String>,
|
pub texture_paths: Vec<String>,
|
||||||
|
|
@ -60,6 +61,7 @@ impl Mdl {
|
||||||
let skin_table = read_relative::<u16, _>(data, header.skin_reference_indexes())?;
|
let skin_table = read_relative::<u16, _>(data, header.skin_reference_indexes())?;
|
||||||
let bones = read_relative(data, header.bone_indexes())?;
|
let bones = read_relative(data, header.bone_indexes())?;
|
||||||
let bone_controllers = read_relative(data, header.bone_controller_indexes())?;
|
let bone_controllers = read_relative(data, header.bone_controller_indexes())?;
|
||||||
|
let body_table_by_name = read_relative(data, header.bone_table_by_name_indexes())?;
|
||||||
|
|
||||||
let surface_prop = read_single(data, header.surface_prop_index)?;
|
let surface_prop = read_single(data, header.surface_prop_index)?;
|
||||||
let key_values = (header.key_value_size > 0)
|
let key_values = (header.key_value_size > 0)
|
||||||
|
|
@ -91,6 +93,7 @@ impl Mdl {
|
||||||
name,
|
name,
|
||||||
bones,
|
bones,
|
||||||
bone_controllers,
|
bone_controllers,
|
||||||
|
body_table_by_name,
|
||||||
body_parts: header
|
body_parts: header
|
||||||
.body_part_indexes()
|
.body_part_indexes()
|
||||||
.map(|index| {
|
.map(|index| {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use cgmath::{Matrix4, SquareMatrix};
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||||
|
|
@ -84,10 +85,20 @@ static_assertions::const_assert_eq!(size_of::<AnimationDescriptionHeader>(), 100
|
||||||
pub struct AnimationDescription {
|
pub struct AnimationDescription {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub fps: f32,
|
pub fps: f32,
|
||||||
pub frame_count: i32,
|
pub frame_count: usize,
|
||||||
pub animations: Vec<Animation>,
|
pub animations: Vec<Animation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AnimationDescription {
|
||||||
|
pub fn get_bone_transform(&self, bone: u8, frame: usize) -> Matrix4<f32> {
|
||||||
|
let Some(animation) = self.animations.iter().find(|anim| anim.bone == bone) else {
|
||||||
|
return Matrix4::identity();
|
||||||
|
};
|
||||||
|
Matrix4::from_translation(animation.position(frame).into())
|
||||||
|
* Matrix4::from(animation.rotation(frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ReadRelative for AnimationDescription {
|
impl ReadRelative for AnimationDescription {
|
||||||
type Header = AnimationDescriptionHeader;
|
type Header = AnimationDescriptionHeader;
|
||||||
|
|
||||||
|
|
@ -110,7 +121,7 @@ impl ReadRelative for AnimationDescription {
|
||||||
Ok(AnimationDescription {
|
Ok(AnimationDescription {
|
||||||
name: read_single(data, header.name_offset)?,
|
name: read_single(data, header.name_offset)?,
|
||||||
fps: header.fps,
|
fps: header.fps,
|
||||||
frame_count: header.frame_count,
|
frame_count: header.frame_count as usize,
|
||||||
animations,
|
animations,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -234,20 +245,43 @@ impl<'a> FrameValues<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum RotationData {
|
pub enum RotationData {
|
||||||
Quaternion48(Quaternion48),
|
Quaternion48(Quaternion),
|
||||||
Quaternion64(Quaternion64),
|
Quaternion64(Quaternion),
|
||||||
RotationValues(Vec<RadianEuler>),
|
Animated(Vec<RadianEuler>),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Quaternion48> for RotationData {
|
||||||
|
fn from(value: Quaternion48) -> Self {
|
||||||
|
let q = Quaternion::from(value);
|
||||||
|
RotationData::Quaternion48(q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Quaternion64> for RotationData {
|
||||||
|
fn from(value: Quaternion64) -> Self {
|
||||||
|
let q = Quaternion::from(value);
|
||||||
|
RotationData::Quaternion64(q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<RadianEuler>> for RotationData {
|
||||||
|
fn from(value: Vec<RadianEuler>) -> Self {
|
||||||
|
// axis get fixed up when applying the scale
|
||||||
|
RotationData::Animated(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RotationData {
|
impl RotationData {
|
||||||
pub fn rotation(&self, frame: usize) -> Quaternion {
|
pub fn rotation(&self, frame: usize) -> Quaternion {
|
||||||
match self {
|
match self {
|
||||||
RotationData::Quaternion48(q) => Quaternion::from(*q),
|
RotationData::Quaternion48(q) => *q,
|
||||||
RotationData::Quaternion64(q) => Quaternion::from(*q),
|
RotationData::Quaternion64(q) => *q,
|
||||||
RotationData::RotationValues(values) => {
|
RotationData::Animated(values) => values
|
||||||
values.get(frame).copied().unwrap_or_default().into()
|
.get(frame)
|
||||||
}
|
.copied()
|
||||||
|
.unwrap_or_else(|| values.last().copied().unwrap_or_default())
|
||||||
|
.into(),
|
||||||
RotationData::None => Quaternion::default(),
|
RotationData::None => Quaternion::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -256,18 +290,19 @@ impl RotationData {
|
||||||
match self {
|
match self {
|
||||||
RotationData::Quaternion48(_) => size_of::<Quaternion48>(),
|
RotationData::Quaternion48(_) => size_of::<Quaternion48>(),
|
||||||
RotationData::Quaternion64(_) => size_of::<Quaternion64>(),
|
RotationData::Quaternion64(_) => size_of::<Quaternion64>(),
|
||||||
RotationData::RotationValues(_) => size_of::<AnimationValuePointer>(),
|
RotationData::Animated(_) => size_of::<AnimationValuePointer>(),
|
||||||
RotationData::None => 0,
|
RotationData::None => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scale(&mut self, scale: Vector) {
|
fn set_scale(&mut self, scale: Vector) {
|
||||||
if let RotationData::RotationValues(values) = self {
|
if let RotationData::Animated(values) = self {
|
||||||
values.iter_mut().for_each(|value| {
|
values.iter_mut().for_each(|value| {
|
||||||
|
// scale and fixup the angles
|
||||||
*value = RadianEuler {
|
*value = RadianEuler {
|
||||||
x: value.x * scale.x,
|
y: value.x * scale.x,
|
||||||
y: value.y * scale.y,
|
z: value.y * scale.y,
|
||||||
z: value.z * scale.z,
|
x: value.z * scale.z,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -317,6 +352,10 @@ impl Animation {
|
||||||
self.rotation_data.rotation(frame)
|
self.rotation_data.rotation(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rotation_looks_valid(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
pub fn position(&self, frame: usize) -> Vector {
|
pub fn position(&self, frame: usize) -> Vector {
|
||||||
self.position_data.position(frame)
|
self.position_data.position(frame)
|
||||||
}
|
}
|
||||||
|
|
@ -343,17 +382,17 @@ fn read_animation(
|
||||||
let offset = size_of::<AnimationHeader>();
|
let offset = size_of::<AnimationHeader>();
|
||||||
|
|
||||||
let rotation_data = if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT) {
|
let rotation_data = if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT) {
|
||||||
RotationData::Quaternion48(read_single(data, offset)?)
|
RotationData::from(read_single::<Quaternion48, _>(data, offset)?)
|
||||||
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT2) {
|
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT2) {
|
||||||
RotationData::Quaternion64(read_single(data, offset)?)
|
RotationData::from(read_single::<Quaternion64, _>(data, offset)?)
|
||||||
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMROT) {
|
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMROT) {
|
||||||
let pointers: AnimationValuePointer = read_single(data, offset)?;
|
let pointers: AnimationValuePointer = read_single(data, offset)?;
|
||||||
let value_data = &data[offset..];
|
let value_data = &data[offset..];
|
||||||
let values = (0..frames)
|
let values: Vec<RadianEuler> = (0..frames)
|
||||||
.map(|frame| read_animation_values(value_data, frame, pointers))
|
.map(|frame| read_animation_values(value_data, frame, pointers))
|
||||||
.map(|r| r.map(|[x, y, z]| RadianEuler { x, y, z }))
|
.map(|r| r.map(|[x, y, z]| RadianEuler { x, z, y }))
|
||||||
.collect::<Result<_, ModelError>>()?;
|
.collect::<Result<_, ModelError>>()?;
|
||||||
RotationData::RotationValues(values)
|
RotationData::from(values)
|
||||||
} else {
|
} else {
|
||||||
RotationData::None
|
RotationData::None
|
||||||
};
|
};
|
||||||
|
|
@ -362,8 +401,8 @@ fn read_animation(
|
||||||
let position_data = if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWPOS) {
|
let position_data = if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWPOS) {
|
||||||
PositionData::Vector48(read_single(data, position_offset)?)
|
PositionData::Vector48(read_single(data, position_offset)?)
|
||||||
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMPOS) {
|
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMPOS) {
|
||||||
let pointers: AnimationValuePointer = read_single(data, offset)?;
|
let pointers: AnimationValuePointer = read_single(data, position_offset)?;
|
||||||
let value_data = &data[offset..];
|
let value_data = &data[position_offset..];
|
||||||
let values = (0..frames)
|
let values = (0..frames)
|
||||||
.map(|frame| read_animation_values(value_data, frame, pointers))
|
.map(|frame| read_animation_values(value_data, frame, pointers))
|
||||||
.map(|r| r.map(Vector::from))
|
.map(|r| r.map(Vector::from))
|
||||||
|
|
|
||||||
|
|
@ -139,8 +139,7 @@ pub struct StudioHeader {
|
||||||
|
|
||||||
anim_block_model: i32, // Placeholder for mutable-void*
|
anim_block_model: i32, // Placeholder for mutable-void*
|
||||||
|
|
||||||
// Points to a series of bytes?
|
bone_table_by_name_index: i32,
|
||||||
bone_table_name_index: i32,
|
|
||||||
|
|
||||||
vertex_base: i32, // Placeholder for void*
|
vertex_base: i32, // Placeholder for void*
|
||||||
offset_base: i32, // Placeholder for void*
|
offset_base: i32, // Placeholder for void*
|
||||||
|
|
@ -155,9 +154,9 @@ pub struct StudioHeader {
|
||||||
num_allowed_root_lods: u8,
|
num_allowed_root_lods: u8,
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
unused0: u8, // ??
|
unused0: u8,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
unused1: i32, // ??
|
unused1: i32,
|
||||||
|
|
||||||
flex_controller_ui_count: i32,
|
flex_controller_ui_count: i32,
|
||||||
flex_controller_ui_index: i32,
|
flex_controller_ui_index: i32,
|
||||||
|
|
@ -219,6 +218,14 @@ impl StudioHeader {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bone_table_by_name_indexes(&self) -> impl Iterator<Item = usize> {
|
||||||
|
index_range(
|
||||||
|
self.bone_table_by_name_index,
|
||||||
|
self.bone_count,
|
||||||
|
size_of::<u8>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hitbox_set_indexes(&self) -> impl Iterator<Item = usize> {
|
pub fn hitbox_set_indexes(&self) -> impl Iterator<Item = usize> {
|
||||||
index_range(
|
index_range(
|
||||||
self.hitbox_set_offset,
|
self.hitbox_set_offset,
|
||||||
|
|
@ -235,10 +242,6 @@ impl StudioHeader {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_sequence_indexes(&self) -> impl Iterator<Item = usize> {
|
|
||||||
index_range(self.local_seq_offset, self.local_seq_count, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn texture_indexes(&self) -> impl Iterator<Item = usize> {
|
pub fn texture_indexes(&self) -> impl Iterator<Item = usize> {
|
||||||
index_range(
|
index_range(
|
||||||
self.texture_offset,
|
self.texture_offset,
|
||||||
|
|
|
||||||
|
|
@ -130,10 +130,33 @@ impl From<cgmath::Quaternion<f32>> for Quaternion {
|
||||||
|
|
||||||
impl From<Quaternion> for cgmath::Matrix4<f32> {
|
impl From<Quaternion> for cgmath::Matrix4<f32> {
|
||||||
fn from(q: Quaternion) -> Self {
|
fn from(q: Quaternion) -> Self {
|
||||||
|
// cgmath::Quaternion::from(Quaternion {
|
||||||
|
// x: q.z,
|
||||||
|
// y: -q.y,
|
||||||
|
// z: q.x,
|
||||||
|
// w: q.w,
|
||||||
|
// })
|
||||||
|
// .into()
|
||||||
cgmath::Quaternion::from(q).into()
|
cgmath::Quaternion::from(q).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Mul for Quaternion {
|
||||||
|
type Output = Quaternion;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
(cgmath::Quaternion::from(self) * cgmath::Quaternion::from(rhs)).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<RadianEuler> for Quaternion {
|
||||||
|
type Output = Quaternion;
|
||||||
|
|
||||||
|
fn mul(self, rhs: RadianEuler) -> Self::Output {
|
||||||
|
(cgmath::Quaternion::from(self) * cgmath::Quaternion::from(rhs)).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Zeroable, Pod, Default)]
|
#[derive(Debug, Clone, Copy, Zeroable, Pod, Default)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct RadianEuler {
|
pub struct RadianEuler {
|
||||||
|
|
@ -165,10 +188,9 @@ impl From<RadianEuler> for Euler<Deg<f32>> {
|
||||||
impl From<RadianEuler> for cgmath::Quaternion<f32> {
|
impl From<RadianEuler> for cgmath::Quaternion<f32> {
|
||||||
fn from(value: RadianEuler) -> Self {
|
fn from(value: RadianEuler) -> Self {
|
||||||
// angles are applied in roll, pitch, yaw order
|
// angles are applied in roll, pitch, yaw order
|
||||||
// additionally the access are remapped
|
|
||||||
cgmath::Quaternion::from_angle_y(Rad(value.y))
|
cgmath::Quaternion::from_angle_y(Rad(value.y))
|
||||||
* cgmath::Quaternion::from_angle_x(Rad(-value.z))
|
* cgmath::Quaternion::from_angle_x(Rad(-value.x))
|
||||||
* cgmath::Quaternion::from_angle_z(Rad(value.x))
|
* cgmath::Quaternion::from_angle_z(Rad(value.z))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,6 +200,12 @@ impl From<RadianEuler> for Quaternion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<RadianEuler> for Matrix4<f32> {
|
||||||
|
fn from(value: RadianEuler) -> Self {
|
||||||
|
cgmath::Quaternion::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Fixed length, null-terminated string
|
/// Fixed length, null-terminated string
|
||||||
#[derive(Debug, Clone, Default, Copy)]
|
#[derive(Debug, Clone, Default, Copy)]
|
||||||
pub struct FixedString<const LEN: usize>(ArrayString<LEN>);
|
pub struct FixedString<const LEN: usize>(ArrayString<LEN>);
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ pub struct BoneWeights {
|
||||||
impl BoneWeights {
|
impl BoneWeights {
|
||||||
pub fn weights(&self) -> impl Iterator<Item = BoneWeight> + '_ {
|
pub fn weights(&self) -> impl Iterator<Item = BoneWeight> + '_ {
|
||||||
(0..min(self.bone_count as usize, 3)).map(|i| BoneWeight {
|
(0..min(self.bone_count as usize, 3)).map(|i| BoneWeight {
|
||||||
weight: self.weight[i],
|
weight: self.weight[i] / self.bone_count as f32,
|
||||||
bone_id: self.bone[i],
|
bone_id: self.bone[i],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue