mirror of
https://github.com/LazyDuchess/OpenTS2.git
synced 2025-01-22 16:21:47 -05:00
Read keyframes from animation data
This commit is contained in:
parent
835df69750
commit
eff377ac14
1 changed files with 210 additions and 14 deletions
|
@ -1,4 +1,5 @@
|
|||
using OpenTS2.Files.Utils;
|
||||
using System;
|
||||
using OpenTS2.Files.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
||||
|
@ -27,6 +28,163 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
|||
|
||||
public uint BoneHash;
|
||||
public uint ChannelFlags;
|
||||
|
||||
public ChannelComponent[] Components;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is where the actual animation keyframes live. Each animation channel can have multiple of these.
|
||||
/// </summary>
|
||||
public class ChannelComponent
|
||||
{
|
||||
public DataType Type;
|
||||
public CurveType TangentCurveType;
|
||||
public int NumKeyFrames;
|
||||
public IKeyFrame[] KeyFrames;
|
||||
|
||||
internal void ReadKeyFrames(IoBuffer reader)
|
||||
{
|
||||
KeyFrames = new IKeyFrame[NumKeyFrames];
|
||||
|
||||
for (var i = 0; i < NumKeyFrames; i++)
|
||||
{
|
||||
if (TangentCurveType == CurveType.BakedTangents)
|
||||
{
|
||||
var keyframe = new IKeyFrame.BakedKeyFrame();
|
||||
KeyFrames[i] = keyframe;
|
||||
|
||||
var data = 0.0f;
|
||||
if (Type == DataType.FloatingPoint32)
|
||||
{
|
||||
keyframe.Data = reader.ReadFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: convert from fixed point to floating point here.
|
||||
reader.ReadUInt16();
|
||||
}
|
||||
} else if (TangentCurveType == CurveType.ContinuousTangents)
|
||||
{
|
||||
var keyframe = new IKeyFrame.ContinuousKeyFrame();
|
||||
KeyFrames[i] = keyframe;
|
||||
|
||||
keyframe.Short1 = reader.ReadUInt16();
|
||||
|
||||
if (Type == DataType.FloatingPoint32)
|
||||
{
|
||||
keyframe.Data = reader.ReadFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: convert from fixed point to floating point here.
|
||||
reader.ReadUInt16();
|
||||
}
|
||||
|
||||
keyframe.Short2 = reader.ReadInt16();
|
||||
} else if (TangentCurveType == CurveType.DiscontinuousTangents)
|
||||
{
|
||||
var keyframe = new IKeyFrame.DiscontinuousKeyFrame();
|
||||
KeyFrames[i] = keyframe;
|
||||
|
||||
keyframe.Short1 = reader.ReadUInt16();
|
||||
if (Type == DataType.FloatingPoint32)
|
||||
{
|
||||
keyframe.Data = reader.ReadFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: convert from fixed point to floating point here.
|
||||
reader.ReadUInt16();
|
||||
}
|
||||
|
||||
keyframe.Short2 = reader.ReadInt16();
|
||||
keyframe.Short3 = reader.ReadInt16();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum CurveType
|
||||
{
|
||||
BakedTangents = 0,
|
||||
ContinuousTangents = 1,
|
||||
DiscontinuousTangents = 2,
|
||||
}
|
||||
|
||||
public static CurveType ChannelCurveTypeFromPackedByte(byte packedByte)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(CurveType), packedByte & 0b11))
|
||||
{
|
||||
throw new ArgumentException($"Invalid curve type: {packedByte & 0b11}");
|
||||
}
|
||||
return (CurveType)(packedByte & 0b11);
|
||||
}
|
||||
|
||||
public enum DataType
|
||||
{
|
||||
/// 8.7 fixed point
|
||||
FixedPoint8_7,
|
||||
/// 9.7 fixed point
|
||||
FixedPoint9_7,
|
||||
|
||||
/// 5.10 Fixed point
|
||||
FixedPoint5_10,
|
||||
/// 5.11 fixed point
|
||||
FixedPoint5_11,
|
||||
|
||||
/// 3.12 fixed point
|
||||
FixedPoint3_12,
|
||||
/// 3.13 fixed point
|
||||
FixedPoint3_13,
|
||||
|
||||
/// plain floats.
|
||||
FloatingPoint32,
|
||||
}
|
||||
|
||||
public static DataType ChannelDataTypeFromSerializedPackedByte(byte packedByte) {
|
||||
// 5th bit set is float.
|
||||
if ((packedByte & 0b10000) != 0)
|
||||
{
|
||||
return DataType.FloatingPoint32;
|
||||
}
|
||||
|
||||
// Next check the top 3 (out of 5) bits and the curve type.
|
||||
var topThreeBits = (packedByte >> 2 & 0b111);
|
||||
var curveType = ChannelCurveTypeFromPackedByte(packedByte);
|
||||
return topThreeBits switch
|
||||
{
|
||||
0b000 when curveType == CurveType.BakedTangents => DataType.FixedPoint8_7,
|
||||
0b000 => DataType.FixedPoint9_7,
|
||||
0b001 when curveType == CurveType.BakedTangents => DataType.FixedPoint5_10,
|
||||
0b001 => DataType.FixedPoint5_11,
|
||||
0b011 when curveType == CurveType.BakedTangents => DataType.FixedPoint3_12,
|
||||
0b011 => DataType.FixedPoint3_13,
|
||||
_ => throw new ArgumentException($"Invalid data type: {packedByte}")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IKeyFrame
|
||||
{
|
||||
public struct BakedKeyFrame : IKeyFrame
|
||||
{
|
||||
public float Data;
|
||||
}
|
||||
|
||||
public struct ContinuousKeyFrame : IKeyFrame
|
||||
{
|
||||
public ushort Short1;
|
||||
public float Data;
|
||||
public short Short2;
|
||||
}
|
||||
|
||||
public struct DiscontinuousKeyFrame : IKeyFrame
|
||||
{
|
||||
public ushort Short1;
|
||||
public float Data;
|
||||
public short Short2;
|
||||
public short Short3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,8 +222,7 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
|||
var preStretchFactor = reader.ReadFloat();
|
||||
var rootStretchDisplacement = reader.ReadFloat();
|
||||
|
||||
// We need to note the stream position here because the rest of the data is aligned on 4-byte boundaries
|
||||
// sometimes.
|
||||
// We need to note the stream position here because string data is aligned on 4-byte boundaries sometimes.
|
||||
var initialStreamPosition = reader.Stream.Position;
|
||||
|
||||
var skeletonTag = reader.ReadNullTerminatedString();
|
||||
|
@ -95,11 +252,12 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
|||
reader.ReadBytes(4 * 3);
|
||||
}
|
||||
|
||||
// Another aligned section... the names of each animation target's targetted tag.
|
||||
initialStreamPosition = reader.Stream.Position;
|
||||
for (var i = 0; i < numAnimTargets; i++)
|
||||
{
|
||||
animTargets[i].TagName = reader.ReadNullTerminatedString();
|
||||
}
|
||||
|
||||
ReadPadding(reader, reader.Stream.Position - initialStreamPosition);
|
||||
|
||||
for (var i = 0; i < numAnimTargets; i++)
|
||||
|
@ -116,9 +274,19 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
|||
reader.ReadUInt32(); // 1 ignored uint32.
|
||||
channel.ChannelFlags = reader.ReadUInt32();
|
||||
reader.ReadUInt32(); // 1 ignored uint32.
|
||||
|
||||
// Channel types and their order:
|
||||
// ChannelTypeF1
|
||||
// ChannelTypeF3
|
||||
// ChannelTypeF4
|
||||
// ChannelTypeQ
|
||||
// ChannelTypeXYZ
|
||||
// ChannelTypeF2
|
||||
}
|
||||
}
|
||||
|
||||
// Another aligned section... the names of each of the animation channels.
|
||||
initialStreamPosition = reader.Stream.Position;
|
||||
for (var i = 0; i < numAnimTargets; i++)
|
||||
{
|
||||
var target = animTargets[i];
|
||||
|
@ -127,22 +295,41 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
|||
target.Channels[j].ChannelName = reader.ReadNullTerminatedString();
|
||||
}
|
||||
}
|
||||
|
||||
ReadPadding(reader, reader.Stream.Position - initialStreamPosition);
|
||||
|
||||
for (var i = 0; i < numAnimTargets; i++)
|
||||
// Next up the number of animation components in each channel and its keyframe types.
|
||||
foreach (var target in animTargets)
|
||||
{
|
||||
var target = animTargets[i];
|
||||
for (var j = 0; j < target.NumSharedChannels; j++)
|
||||
foreach (var channel in target.Channels)
|
||||
{
|
||||
var numComponents = (target.Channels[j].ChannelFlags >> 5) & 0b111;
|
||||
var numComponents = (channel.ChannelFlags >> 5) & 0b111;
|
||||
channel.Components = new AnimResourceConstBlock.ChannelComponent[numComponents];
|
||||
|
||||
for (var k = 0; k < numComponents; k++)
|
||||
{
|
||||
// The exact format here depends on some flags...
|
||||
// for now this is just from the wiki.
|
||||
reader.ReadUInt16();
|
||||
reader.ReadInt16();
|
||||
reader.ReadUInt32();
|
||||
var component = new AnimResourceConstBlock.ChannelComponent();
|
||||
channel.Components[k] = component;
|
||||
|
||||
component.NumKeyFrames = reader.ReadUInt16();
|
||||
var dataType = reader.ReadByte();
|
||||
reader.ReadBytes(1 + 4); // 1 ignored byte and 1 ignored uint32.
|
||||
|
||||
component.Type =
|
||||
AnimResourceConstBlock.ChannelComponent.ChannelDataTypeFromSerializedPackedByte(dataType);
|
||||
component.TangentCurveType =
|
||||
AnimResourceConstBlock.ChannelComponent.ChannelCurveTypeFromPackedByte(dataType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now the actual keyframe data.
|
||||
foreach (var target in animTargets)
|
||||
{
|
||||
foreach (var channel in target.Channels)
|
||||
{
|
||||
foreach (var component in channel.Components)
|
||||
{
|
||||
component.ReadKeyFrames(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +340,15 @@ namespace OpenTS2.Files.Formats.DBPF.Scenegraph.Block
|
|||
foreach (var channel in target.Channels)
|
||||
{
|
||||
Debug.Log($" name: {channel.ChannelName}, bonehash: {channel.BoneHash:X}");
|
||||
|
||||
foreach (var component in channel.Components)
|
||||
{
|
||||
Debug.Log($" numKeyFrames: {component.NumKeyFrames}, type: {component.Type}, tangentType: {component.TangentCurveType}");
|
||||
foreach (var keyframe in component.KeyFrames)
|
||||
{
|
||||
Debug.Log($" {keyframe.GetType()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue