1
0
mirror of synced 2025-02-21 13:00:52 +01:00

Parse the skeletal animation format CSAB

This commit is contained in:
KillzXGaming 2019-08-03 19:33:29 -04:00
parent 89aecaec34
commit 1f8bd2e19e
2 changed files with 147 additions and 3 deletions

Binary file not shown.

View File

@ -65,13 +65,23 @@ namespace FirstPlugin
LM3DS,
}
public enum AnimationTrackType
{
LINEAR = 0x01,
HERMITE = 0x02,
};
public class Header
{
public GameVersion Version;
public List<AnimationNode> Nodes = new List<AnimationNode>();
public void Read(FileReader reader)
{
reader.CheckSignature(4, "csab");
reader.SetByteOrder(false);
reader.ReadSignature(4, "csab");
uint FileSize = reader.ReadUInt32();
uint versionNum = reader.ReadUInt32();
if (versionNum == 5)
@ -94,17 +104,151 @@ namespace FirstPlugin
uint unknown5 = reader.ReadUInt32();//0x00
uint unknown6 = reader.ReadUInt32();//0x00
uint unknown7 = reader.ReadUInt32();//0x00
uint unknown8 = reader.ReadUInt32();//0x00
uint duration = reader.ReadUInt32();
uint nodeCount = reader.ReadUInt32();
uint boneCount = reader.ReadUInt32();
if (nodeCount != boneCount) throw new Exception("Unexpected bone and node count!");
ushort[] BoneIndexTable = reader.ReadUInt16s((int)boneCount);
for (int i = 0; i < boneCount; i++)
reader.Align(4);
uint[] nodeOffsets = reader.ReadUInt32s((int)nodeCount);
for (int i = 0; i < nodeCount; i++)
{
reader.SeekBegin(nodeOffsets[i] + 0x18);
AnimationNode node = new AnimationNode();
node.Read(reader, Version);
Nodes.Add(node);
}
}
}
public class AnimationNode
{
public ushort BoneIndex { get; set; }
public AnimTrack TranslateX { get; set; }
public AnimTrack TranslateY { get; set; }
public AnimTrack TranslateZ { get; set; }
public AnimTrack RotationX { get; set; }
public AnimTrack RotationY { get; set; }
public AnimTrack RotationZ { get; set; }
public AnimTrack ScaleX { get; set; }
public AnimTrack ScaleY { get; set; }
public AnimTrack ScaleZ { get; set; }
public void Read(FileReader reader, GameVersion version)
{
long pos = reader.Position;
reader.ReadSignature(4, "anod");
BoneIndex = reader.ReadUInt16();
reader.ReadUInt16();//0x00
TranslateX = ParseTrack(reader, version, pos);
TranslateY = ParseTrack(reader, version, pos);
TranslateZ = ParseTrack(reader, version, pos);
RotationX = ParseTrack(reader, version, pos);
RotationY = ParseTrack(reader, version, pos);
RotationZ = ParseTrack(reader, version, pos);
ScaleX = ParseTrack(reader, version, pos);
ScaleY = ParseTrack(reader, version, pos);
ScaleZ = ParseTrack(reader, version, pos);
reader.ReadUInt16();//0x00
}
}
private static AnimTrack ParseTrack(FileReader reader, GameVersion version, long startPos)
{
long pos = reader.Position;
uint Offset = reader.ReadUInt16();
if (Offset == 0) return null;
reader.SeekBegin(startPos + Offset);
var track = new AnimTrack(reader, version);
reader.SeekBegin(pos + sizeof(ushort)); //Seek back to next offset
return track;
}
public class AnimTrack
{
public List<LinearKeyFrame> KeyFramesLinear = new List<LinearKeyFrame>();
public List<HermiteKeyFrame> KeyFramesHermite = new List<HermiteKeyFrame>();
public uint InterpolationType;
public AnimTrack(FileReader reader, GameVersion version)
{
uint numKeyFrames =0;
if (version >= GameVersion.MM3D)
{
InterpolationType = reader.ReadByte();
numKeyFrames = reader.ReadUInt16();
}
else
{
InterpolationType = reader.ReadUInt32();
numKeyFrames = reader.ReadUInt32();
uint unknown = reader.ReadUInt32();
uint endFrame = reader.ReadUInt32();
}
if (InterpolationType == (uint)AnimationTrackType.LINEAR)
{
if (version >= GameVersion.MM3D)
{
float scale = reader.ReadSingle();
float bias = reader.ReadSingle();
for (uint i = 0; i < numKeyFrames; i++)
{
LinearKeyFrame keyFrame = new LinearKeyFrame();
keyFrame.Time = i;
keyFrame.Value = reader.ReadUInt16() * scale - bias;
KeyFramesLinear.Add(keyFrame);
}
}
else
{
for (int i = 0; i < numKeyFrames; i++)
{
LinearKeyFrame keyFrame = new LinearKeyFrame();
keyFrame.Time = reader.ReadUInt32();
keyFrame.Value = reader.ReadSingle();
KeyFramesLinear.Add(keyFrame);
}
}
}
else if (InterpolationType == (uint)AnimationTrackType.HERMITE)
{
for (int i = 0; i < numKeyFrames; i++)
{
HermiteKeyFrame keyFrame = new HermiteKeyFrame();
keyFrame.Time = reader.ReadUInt32();
keyFrame.Value = reader.ReadSingle();
keyFrame.TangentIn = reader.ReadSingle();
keyFrame.TangentOut = reader.ReadSingle();
KeyFramesHermite.Add(keyFrame);
}
}
else
throw new Exception("Unknown interpolation type! " + InterpolationType);
}
}
public class HermiteKeyFrame
{
public uint Time { get; set; }
public float Value { get; set; }
public float TangentIn { get; set; }
public float TangentOut { get; set; }
}
public class LinearKeyFrame
{
public uint Time { get; set; }
public float Value { get; set; }
}
}
}