mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-04 00:54:14 +02:00
more anim work
This commit is contained in:
parent
1e599c380a
commit
226d085211
4 changed files with 73 additions and 41 deletions
12
src/lib.rs
12
src/lib.rs
|
|
@ -211,14 +211,14 @@ impl Model {
|
||||||
.map(|(_, weight)| weight.weight)
|
.map(|(_, weight)| weight.weight)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
let pose_to_bone = animated_bone.pos.into();
|
let pose_to_bone: Matrix4<f32> = animated_bone.pose_to_bone.into();
|
||||||
|
let bone_to_pose: Matrix4<f32> = pose_to_bone.inverse_transform().unwrap();
|
||||||
|
let bone_rotation: Matrix4<f32> = animated_bone.rot.into();
|
||||||
|
|
||||||
let bone_rotation = Matrix4::from(animated_bone.rot);
|
|
||||||
if weight > 0.0 {
|
if weight > 0.0 {
|
||||||
position -= pose_to_bone;
|
let transform =
|
||||||
let transform = (animation.transform(frame)) * bone_rotation;
|
bone_to_pose * animation.transform(frame) * bone_rotation * pose_to_bone;
|
||||||
position = transform.transform_vector(position);
|
position = transform.transform_point(position);
|
||||||
position += pose_to_bone;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,10 +155,22 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Zeroable, Pod, Copy, Clone, Debug)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[repr(C)]
|
struct AnimationValuePointers<'a> {
|
||||||
struct AnimationValuePointer([u16; 3]);
|
offsets: [u16; 3],
|
||||||
impl ReadableRelative for AnimationValuePointer {}
|
data: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ReadRelative<'a> for AnimationValuePointers<'a> {
|
||||||
|
type Header = [u16; 3];
|
||||||
|
|
||||||
|
fn read(data: &'a [u8], header: Self::Header) -> Result<Self, ModelError> {
|
||||||
|
Ok(AnimationValuePointers {
|
||||||
|
offsets: header,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Zeroable, Pod, Copy, Clone, Debug, Default)]
|
#[derive(Zeroable, Pod, Copy, Clone, Debug, Default)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
@ -172,17 +184,16 @@ static_assertions::const_assert_eq!(size_of::<ValueHeader>(), size_of::<i16>());
|
||||||
impl ReadableRelative for ValueHeader {}
|
impl ReadableRelative for ValueHeader {}
|
||||||
|
|
||||||
fn read_animation_values(
|
fn read_animation_values(
|
||||||
data: &[u8], // data starting at the AnimationValuePointer
|
|
||||||
frame: usize,
|
frame: usize,
|
||||||
base_pointers: AnimationValuePointer,
|
animation_value_pointers: AnimationValuePointers,
|
||||||
) -> Result<[f32; 3], ModelError> {
|
) -> Result<[f32; 3], ModelError> {
|
||||||
let [x, y, z] = base_pointers
|
let [x, y, z] = animation_value_pointers
|
||||||
.0
|
.offsets
|
||||||
.map::<_, Result<_, ModelError>>(|base_pointer| {
|
.map::<_, Result<_, ModelError>>(|offset| {
|
||||||
if base_pointer == 0 {
|
if offset == 0 {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
let values: FrameValues = read_single(data, base_pointer)?;
|
let values: FrameValues = read_single(animation_value_pointers.data, offset)?;
|
||||||
Ok(values.get(frame as u8)?)
|
Ok(values.get(frame as u8)?)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -291,7 +302,9 @@ 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::Animated(_) => size_of::<AnimationValuePointer>(),
|
RotationData::Animated(_) => {
|
||||||
|
size_of::<<AnimationValuePointers<'_> as ReadRelative>::Header>()
|
||||||
|
}
|
||||||
RotationData::None => 0,
|
RotationData::None => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -332,7 +345,10 @@ impl PositionData {
|
||||||
pub fn position(&self, frame: usize) -> Vector {
|
pub fn position(&self, frame: usize) -> Vector {
|
||||||
match self {
|
match self {
|
||||||
PositionData::Vector48(vector) => Vector::from(*vector),
|
PositionData::Vector48(vector) => Vector::from(*vector),
|
||||||
PositionData::PositionValues(values) => values.get(frame).copied().unwrap_or_default(),
|
PositionData::PositionValues(values) => values
|
||||||
|
.get(frame)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_else(|| values.last().copied().unwrap_or_default()),
|
||||||
PositionData::None => Vector::default(),
|
PositionData::None => Vector::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -364,12 +380,13 @@ impl Animation {
|
||||||
self.rotation_data.rotation(frame)
|
self.rotation_data.rotation(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position(&self, frame: usize) -> Vector {
|
pub fn translation(&self, frame: usize) -> Vector {
|
||||||
self.position_data.position(frame)
|
self.position_data.position(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(&self, frame: usize) -> Matrix4<f32> {
|
pub fn transform(&self, frame: usize) -> Matrix4<f32> {
|
||||||
Matrix4::from_translation(self.position(frame).into()) * Matrix4::from(self.rotation(frame))
|
Matrix4::from(self.rotation(frame))
|
||||||
|
* Matrix4::from_translation(self.translation(frame).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn apply_bone_data(&mut self, bone: &Bone) {
|
pub(crate) fn apply_bone_data(&mut self, bone: &Bone) {
|
||||||
|
|
@ -399,10 +416,9 @@ fn read_animation(
|
||||||
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT2) {
|
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT2) {
|
||||||
RotationData::from(read_single::<Quaternion64, _>(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: AnimationValuePointers = read_single(data, offset)?;
|
||||||
let value_data = &data[offset..];
|
|
||||||
let values: Vec<RadianEuler> = (0..frames)
|
let values: Vec<RadianEuler> = (0..frames)
|
||||||
.map(|frame| read_animation_values(value_data, frame, pointers))
|
.map(|frame| read_animation_values(frame, pointers))
|
||||||
.map_ok(|[pitch, yaw, roll]| RadianEuler { pitch, yaw, roll })
|
.map_ok(|[pitch, yaw, roll]| RadianEuler { pitch, yaw, roll })
|
||||||
.collect::<Result<_, ModelError>>()?;
|
.collect::<Result<_, ModelError>>()?;
|
||||||
RotationData::from(values)
|
RotationData::from(values)
|
||||||
|
|
@ -414,10 +430,9 @@ 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, position_offset)?;
|
let pointers: AnimationValuePointers = read_single(data, position_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(frame, pointers))
|
||||||
.map_ok(Vector::from)
|
.map_ok(Vector::from)
|
||||||
.collect::<Result<_, ModelError>>()?;
|
.collect::<Result<_, ModelError>>()?;
|
||||||
PositionData::PositionValues(values)
|
PositionData::PositionValues(values)
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,12 @@ impl Display for BoneId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq<u8> for BoneId {
|
||||||
|
fn eq(&self, other: &u8) -> bool {
|
||||||
|
self.0 == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct BoneHeader {
|
pub struct BoneHeader {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{ModelError, StringError};
|
use crate::{ModelError, StringError};
|
||||||
use arrayvec::ArrayString;
|
use arrayvec::ArrayString;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use cgmath::{Angle, Deg, Euler, InnerSpace, Matrix3, Matrix4, Rad, Rotation3, Transform, Vector3};
|
use cgmath::{Deg, Euler, Matrix3, Matrix4, Point3, Rad, Rotation3, Transform, Vector3};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
@ -35,6 +35,26 @@ impl From<Vector3<f32>> for Vector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Vector> for Point3<f32> {
|
||||||
|
fn from(v: Vector) -> Self {
|
||||||
|
Self {
|
||||||
|
x: v.x,
|
||||||
|
y: v.y,
|
||||||
|
z: v.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Point3<f32>> for Vector {
|
||||||
|
fn from(v: Point3<f32>) -> Self {
|
||||||
|
Self {
|
||||||
|
x: v.x,
|
||||||
|
y: v.y,
|
||||||
|
z: v.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Vector {
|
impl Vector {
|
||||||
pub fn iter(&self) -> impl Iterator<Item = f32> {
|
pub fn iter(&self) -> impl Iterator<Item = f32> {
|
||||||
[self.x, self.y, self.z].into_iter()
|
[self.x, self.y, self.z].into_iter()
|
||||||
|
|
@ -321,23 +341,15 @@ impl Transform3x4 {
|
||||||
mapped_rotation.into()
|
mapped_rotation.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(&self, vec: Vector) -> Vector {
|
|
||||||
let vec: Vector3<f32> = [vec.y, vec.z, vec.x].into();
|
|
||||||
let z = vec.dot(self.x()) + self.transform[0][3];
|
|
||||||
let x = vec.dot(self.y()) + self.transform[1][3];
|
|
||||||
let y = vec.dot(self.z()) + self.transform[2][3];
|
|
||||||
Vector { x, y, z }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rotation(&self) -> Quaternion {
|
pub fn rotation(&self) -> Quaternion {
|
||||||
cgmath::Quaternion::from(self.rotation_matrix()).into()
|
cgmath::Quaternion::from(self.rotation_matrix()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn translate(&self) -> Vector {
|
pub fn translate(&self) -> Vector {
|
||||||
[
|
[
|
||||||
|
self.transform[2][3],
|
||||||
self.transform[0][3],
|
self.transform[0][3],
|
||||||
self.transform[1][3],
|
self.transform[1][3],
|
||||||
self.transform[2][3],
|
|
||||||
]
|
]
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
@ -345,9 +357,8 @@ impl Transform3x4 {
|
||||||
|
|
||||||
impl From<Transform3x4> for Matrix4<f32> {
|
impl From<Transform3x4> for Matrix4<f32> {
|
||||||
fn from(value: Transform3x4) -> Self {
|
fn from(value: Transform3x4) -> Self {
|
||||||
let translate = value.translate();
|
let translate = Matrix4::from_translation(value.translate().into());
|
||||||
let rotate = value.rotation_matrix();
|
let rotate = Matrix4::from(value.rotation_matrix());
|
||||||
let rotate = Matrix4::from(rotate);
|
rotate * translate
|
||||||
rotate * Matrix4::from_translation(translate.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue