Parse the skeletal animation format CSAB
This commit is contained in:
parent
89aecaec34
commit
1f8bd2e19e
Binary file not shown.
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user