Animations XML conversion progress

This commit is contained in:
dexy 2019-11-17 22:14:00 +11:00
parent c98c526b5f
commit baf29066a7
4 changed files with 141 additions and 84 deletions

View File

@ -197,7 +197,7 @@ namespace CodeWalker.GameFiles
// actually we should only export Static for 'real' channels, but as mapping for these is stupid, we'll just repeat the same value even if one channel is supposed to be static
if (seq.Sequences[i].Channels[0] is AnimChannelStaticFloat && seq.Sequences[i].Channels[1] is AnimChannelStaticFloat && seq.Sequences[i].Channels[2] is AnimChannelStaticFloat)
{
var q = seq.Sequences[i].EvaluateQuaternion(0);
var q = seq.Sequences[i].EvaluateQuaternionType7(0);
return $" {q[index]}\r\n";
}
@ -205,7 +205,7 @@ namespace CodeWalker.GameFiles
StringBuilder db = new StringBuilder();
for (int f = 0; f < seq.NumFrames; f++)
{
db.AppendLine($" {seq.Sequences[i].EvaluateQuaternion(f)[index]}");
db.AppendLine($" {seq.Sequences[i].EvaluateQuaternionType7(f)[index]}");
}
return db.ToString();

View File

@ -2990,7 +2990,7 @@ namespace CodeWalker.GameFiles
if (ycd1.ClipDictionary == null)
{ continue; }
var data1 = ycd1.Save();
//var data1 = ycd1.Save();
var t = true;
if (t)//just here to test loading only

View File

@ -533,7 +533,7 @@ namespace CodeWalker.GameFiles
public uint Unknown_08h { get; set; } // 0x00000000
public uint Unknown_0Ch { get; set; } // 0x00000000
public ushort Unknown_10h { get; set; }
public ushort Unknown_12h { get; set; }
public ushort Unknown_12h { get; set; } // 0x0000
public ushort Frames { get; set; }
public ushort SequenceFrameLimit { get; set; }
public float Duration { get; set; }
@ -578,6 +578,20 @@ namespace CodeWalker.GameFiles
this.BoneIds = reader.ReadBlock<ResourceSimpleList64_s<AnimationBoneId>>();
AssignSequenceBoneIds();
switch (Unknown_10h)
{
case 256://0
case 257://1
case 264://8
case 272://16
case 280://24
break;
default: break;
}
if (Unknown_12h != 0)
{ }
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
@ -668,7 +682,6 @@ namespace CodeWalker.GameFiles
{
YcdXml.StringTag(sb, indent, "Hash", YcdXml.HashString(AnimationHash));
YcdXml.ValueTag(sb, indent, "Unknown10", Unknown_10h.ToString());
YcdXml.ValueTag(sb, indent, "Unknown12", Unknown_12h.ToString());
YcdXml.ValueTag(sb, indent, "FrameCount", Frames.ToString());
YcdXml.ValueTag(sb, indent, "SequenceFrameLimit", SequenceFrameLimit.ToString());//sequences should be transparent to this!
YcdXml.ValueTag(sb, indent, "Duration", FloatUtil.ToString(Duration));
@ -681,7 +694,6 @@ namespace CodeWalker.GameFiles
{
AnimationHash = XmlMeta.GetHash(Xml.GetChildInnerText(node, "Hash"));
Unknown_10h = (ushort)Xml.GetChildUIntAttribute(node, "Unknown10", "value");
Unknown_12h = (ushort)Xml.GetChildUIntAttribute(node, "Unknown12", "value");
Frames = (ushort)Xml.GetChildUIntAttribute(node, "FrameCount", "value");
SequenceFrameLimit = (ushort)Xml.GetChildUIntAttribute(node, "SequenceFrameLimit", "value");
Duration = Xml.GetChildFloatAttribute(node, "Duration", "value");
@ -920,6 +932,7 @@ namespace CodeWalker.GameFiles
public float Quantum { get; set; }
public float Offset { get; set; }
public float[] Values { get; set; }
public uint[] ValueList { get; set; }
public uint[] Frames { get; set; }
@ -938,13 +951,17 @@ namespace CodeWalker.GameFiles
Frames = new uint[reader.NumFrames];
int numValues = (NumInts * 32) / ValueBits;
var numValues0 = (NumInts * 32) / ValueBits;
var numValues1 = (1u << FrameBits) - 1;
var numValues = Math.Min(numValues0, numValues1); //any better way to calculate this?
Values = new float[numValues];
ValueList = new uint[numValues];
reader.BitPosition = reader.Position * 8;
for (int i = 0; i < numValues; i++)
{
uint bits = reader.ReadBits(ValueBits);
Values[i] = (bits * Quantum) + Offset;
ValueList[i] = bits;
}
reader.Position += NumInts * 4;
@ -966,20 +983,28 @@ namespace CodeWalker.GameFiles
}
public override void Write(AnimChannelDataWriter writer)
{
var frameBits = Math.Max(writer.BitCount(Frames), 2);
if (frameBits != FrameBits)
{ }
var frameBits = Math.Max(writer.BitCount((uint)((Values?.Length ?? 1))), 2);// Math.Max(writer.BitCount(Frames), 2);
//if ((frameBits != FrameBits)&&(ValueList!=null))
//{ } // ######### DEBUG TEST
FrameBits = frameBits;
var valueCount = Values?.Length ?? 0;
var valueList = new uint[valueCount];
for (int i = 0; i < valueCount; i++)
{
valueList[i] = GetQuanta(Values[i]);
var bits = GetQuanta(Values[i]);
valueList[i] = bits;
//if (ValueList != null) // ######### DEBUG TEST
//{
// var testbits = ValueList[i];
// if (bits != testbits)
// { }
//}
}
var valueBits = Math.Max(writer.BitCount(valueList), 3);
if (valueBits != ValueBits)
{ }
//if ((valueBits != ValueBits)&&(ValueList!=null))
//{ }// ######### DEBUG TEST
ValueBits = valueBits;
writer.ResetBitstream();
@ -1018,7 +1043,7 @@ namespace CodeWalker.GameFiles
private uint GetQuanta(float v)
{
var q = (v - Offset) / Quantum;
return (uint)q;
return (uint)(q + 0.5f);
//return (uint)Math.Round(q, 0);//any better way?
}
@ -1052,6 +1077,7 @@ namespace CodeWalker.GameFiles
public float Quantum { get; set; }
public float Offset { get; set; }
public float[] Values { get; set; }
public uint[] ValueList { get; set; }
public AnimChannelQuantizeFloat()
{
@ -1064,6 +1090,7 @@ namespace CodeWalker.GameFiles
Quantum = reader.ReadSingle();
Offset = reader.ReadSingle();
Values = new float[reader.NumFrames];
ValueList = new uint[reader.NumFrames];
if (ValueBits < 1)
{ }
@ -1074,11 +1101,19 @@ namespace CodeWalker.GameFiles
var valueList = new uint[valueCount];
for (int i = 0; i < valueCount; i++)
{
valueList[i] = GetQuanta(Values[i]);
var bits = GetQuanta(Values[i]);
valueList[i] = bits;
//if (ValueList != null) // ######### DEBUG TEST
//{
// var testbits = ValueList[i];
// if (bits != testbits)
// { }
//}
}
var valueBits = Math.Max(writer.BitCount(valueList), 1);
if (valueBits != ValueBits)
{ }
//if ((valueBits != ValueBits)&&(ValueList!=null))
//{ } // ######### DEBUG TEST
ValueBits = valueBits;
writer.Write(ValueBits);
@ -1089,7 +1124,9 @@ namespace CodeWalker.GameFiles
public override void ReadFrame(AnimChannelDataReader reader)
{
uint bits = reader.ReadFrameBits(ValueBits);
Values[reader.Frame] = (bits * Quantum) + Offset;
float val = (bits * Quantum) + Offset;
Values[reader.Frame] = val;
ValueList[reader.Frame] = bits;
}
public override void WriteFrame(AnimChannelDataWriter writer)
{
@ -1106,7 +1143,7 @@ namespace CodeWalker.GameFiles
private uint GetQuanta(float v)
{
var q = (v - Offset) / Quantum;
return (uint)q;
return (uint)(q + 0.5f);
//return (uint)Math.Round(q, 0);//any better way?
}
@ -1145,6 +1182,7 @@ namespace CodeWalker.GameFiles
private int Count3 { get; set; } //number of delta bits for each frame
public float[] Values { get; set; }
public int[] ValueList { get; set; }
public AnimChannelLinearFloat()
@ -1166,14 +1204,15 @@ namespace CodeWalker.GameFiles
var streamLength = (reader.Data?.Length ?? 0) * 8;
var numFrames = reader.NumFrames;
var numChunks = reader.NumChunks;
var chunkSize = reader.ChunkSize;//64 or 255(-1?)
var numChunks = (ushort)((chunkSize + numFrames - 1) / chunkSize);
var deltaOffset = Bit + (numChunks * (Count1 + Count2));//base offset to delta bits
reader.BitPosition = Bit;
var chunkOffsets = new int[numChunks];
var chunkValues = new int[numChunks];
var frameValues = new float[numFrames];
var frameBits = new int[numFrames];
for (int i = 0; i < numChunks; i++)
{
chunkOffsets[i] = (Count1 > 0) ? (int)reader.ReadBits(Count1) : 0;
@ -1197,6 +1236,7 @@ namespace CodeWalker.GameFiles
if (frame >= numFrames) break;
frameValues[frame] = (value * Quantum) + Offset;
frameBits[frame] = value;
if ((j + 1) >= chunkSize) break;//that's the last frame in the chunk, don't go further
@ -1224,7 +1264,7 @@ namespace CodeWalker.GameFiles
}
}
Values = frameValues;
ValueList = frameBits;
//for (int i = 1; i < numChunks; i++)
//{
@ -1239,18 +1279,25 @@ namespace CodeWalker.GameFiles
public override void Write(AnimChannelDataWriter writer)
{
//TODO: fix this!
var numFrames = writer.NumFrames;
var numChunks = writer.NumChunks;
var numChunks = (ushort)((64 + numFrames - 1) / 64);//default value, if chunks used, chunkSize is always 64!
byte chunkSize = 64; //seems to always be 64 for this
if (writer.ChunkSize != chunkSize)
{ writer.ChunkSize = chunkSize; }
var valueCount = Values?.Length ?? 0;
var valueList = new uint[valueCount];
var valueList = new int[valueCount];
for (int i = 0; i < valueCount; i++)
{
valueList[i] = GetQuanta(Values[i]);
var bits = GetQuanta(Values[i]);
valueList[i] = bits;
//if (ValueList != null) // ######### DEBUG TEST
//{
// var testbits = ValueList[i];
// if (bits != testbits)
// { }
//}
}
@ -1261,17 +1308,17 @@ namespace CodeWalker.GameFiles
for (int i = 0; i < numChunks; i++)
{
var cframe = (i * chunkSize);//chunk start frame
var cvalue = (cframe < valueCount) ? valueList[cframe] : valueList[valueCount - 1];
var cvalue = (cframe < valueCount) ? valueList[cframe] : valueList[0];
var cdeltas = new int[chunkSize];
var cinc = 0;
chunkValues[i] = cvalue;
chunkValues[i] = (uint)cvalue;
chunkDeltas[i] = cdeltas;
for (int j = 1; j < chunkSize; j++)
{
int frame = cframe + j;
if (frame >= numFrames) break;
var value = valueList[frame];
var inc = (int)value - (int)cvalue;
var inc = value - cvalue;
var delta = inc - cinc;
var deltaa = (uint)Math.Abs(delta);
cinc = inc;
@ -1349,10 +1396,11 @@ namespace CodeWalker.GameFiles
}
private uint GetQuanta(float v)
private int GetQuanta(float v)
{
var q = (v - Offset) / Quantum;
return (uint)Math.Round(Math.Max(q, 0));//any better way?
return (int)(q + 0.5f);
//return (uint)Math.Round(Math.Max(q, 0));//any better way?
}
@ -1414,10 +1462,15 @@ namespace CodeWalker.GameFiles
{
float v = Values[writer.Frame];
var b = BitConverter.GetBytes(v);
uint bits = b[0] + (b[1]*256u) + (b[2]*65536u) + (b[3]*16777216u);
var bits = BitConverter.ToUInt32(b, 0);
writer.WriteFrameBits(bits, 32);
}
public override int GetFrameBits()
{
return 32;
}
public override float EvaluateFloat(int frame)
{
if (Values?.Length > 0) return Values[frame % Values.Length];
@ -1519,7 +1572,6 @@ namespace CodeWalker.GameFiles
{
public byte[] Data { get; set; }
public ushort NumFrames { get; set; }
public ushort NumChunks { get; set; }
public byte ChunkSize { get; set; } //stride of channel frame items (in frames)
public int Position { get; set; } //current byte that the main data reader is on
public int Frame { get; set; } //current frame that the reader is on
@ -1535,7 +1587,6 @@ namespace CodeWalker.GameFiles
{
Data = data;
NumFrames = numFrames;
NumChunks = (ushort)((chunkSize + numFrames) / chunkSize);
ChunkSize = chunkSize;
Position = 0;
Frame = 0;
@ -1672,7 +1723,6 @@ namespace CodeWalker.GameFiles
public int Position { get; set; } //current byte that the main data reader is on
public int Frame { get; set; } //current frame that the reader is on
public ushort NumFrames { get; set; }
public ushort NumChunks { get; set; }
public byte ChunkSize { get; set; } //stride of channel frame items - starts at 0 and will be set to 64 if need be
public ushort FrameLength { get; set; } = 0; //stride of frame data item, calculated when ending frames
@ -1693,7 +1743,6 @@ namespace CodeWalker.GameFiles
Position = 0;
Frame = 0;
NumFrames = numFrames;
NumChunks = (ushort)((64 + numFrames) / 64);//default value, if chunks used, chunkSize is always 64!
ChunkSize = 0; //default 0 value means chunks not used
ChannelListWriter = new BinaryWriter(ChannelListStream);
ChannelItemWriter = new BinaryWriter(ChannelItemStream);
@ -1887,7 +1936,7 @@ namespace CodeWalker.GameFiles
public AnimationBoneId BoneId { get; set; }//for convenience
public Quaternion EvaluateQuaternion(int frame)
public Quaternion EvaluateQuaternionType7(int frame)
{
if (!IsType7Quat)
{
@ -1922,10 +1971,16 @@ namespace CodeWalker.GameFiles
}
}
public Quaternion EvaluateQuaternion(int frame)
{
if (IsType7Quat) return EvaluateQuaternionType7(frame);
return EvaluateVector(frame).ToQuaternion();
}
public Vector4 EvaluateVector(int frame)
{
if (Channels == null) return Vector4.Zero;
if (IsType7Quat) return Quaternion.Normalize(EvaluateQuaternion(frame)).ToVector4();//normalization shouldn't be necessary, but saves explosions in case of incorrectness
if (IsType7Quat) return Quaternion.Normalize(EvaluateQuaternionType7(frame)).ToVector4();//normalization shouldn't be necessary, but saves explosions in case of incorrectness
var v = Vector4.Zero;
int c = 0;
for (int i = 0; i < Channels.Length; i++)
@ -2173,6 +2228,7 @@ namespace CodeWalker.GameFiles
var reader = new AnimChannelDataReader(Data, NumFrames, ChunkSize, FrameOffset, FrameLength);
var channelList = new List<AnimChannelListItem>();
var channelLists = new AnimChannel[9][];
var frameOffset = 0;
for (int i = 0; i < 9; i++)//iterate through anim channel types
{
var ctype = (AnimChannelType)i;
@ -2196,6 +2252,8 @@ namespace CodeWalker.GameFiles
}
channel.Associate(sequence, index);
channelList.Add(new AnimChannelListItem(sequence, index, channel));
channel.FrameOffset = frameOffset;
frameOffset += channel.GetFrameBits();
}
}
reader.AlignChannelDataOffset(channelCount);
@ -2527,42 +2585,42 @@ namespace CodeWalker.GameFiles
newRotRefs.Sort((a, b) => { return compare(a, b); });
if (RootPositionRefs != null)
{
if (RootPositionRefs.Length != newPosRefs.Count)
{ }
else
{
for (int i = 0; i < RootPositionRefs.Length; i++)
{
var oldRef = RootPositionRefs[i];
var newRef = newPosRefs[i];
for (int b = 0; b < 2; b++)
{
if (oldRef.Bytes[b] != newRef.Bytes[b])
{ }
}
}
}
}
if (RootRotationRefs != null)
{
if (RootRotationRefs.Length != newRotRefs.Count)
{ }
else
{
for (int i = 0; i < RootRotationRefs.Length; i++)
{
var oldRef = RootRotationRefs[i];
var newRef = newRotRefs[i];
for (int b = 0; b < 2; b++)
{
if (oldRef.Bytes[b] != newRef.Bytes[b])
{ }
}
}
}
}
//if (RootPositionRefs != null)
//{
// if (RootPositionRefs.Length != newPosRefs.Count)
// { }
// else
// {
// for (int i = 0; i < RootPositionRefs.Length; i++)
// {
// var oldRef = RootPositionRefs[i];
// var newRef = newPosRefs[i];
// for (int b = 0; b < 6; b++)
// {
// if (oldRef.Bytes[b] != newRef.Bytes[b])
// { }
// }
// }
// }
//}
//if (RootRotationRefs != null)
//{
// if (RootRotationRefs.Length != newRotRefs.Count)
// { }
// else
// {
// for (int i = 0; i < RootRotationRefs.Length; i++)
// {
// var oldRef = RootRotationRefs[i];
// var newRef = newRotRefs[i];
// for (int b = 0; b < 6; b++)
// {
// if (oldRef.Bytes[b] != newRef.Bytes[b])
// { }
// }
// }
// }
//}
RootPositionRefs = (newPosRefs.Count > 0) ? newPosRefs.ToArray() : null;

View File

@ -536,8 +536,8 @@ namespace CodeWalker.Rendering
bone.AnimTranslation = v.XYZ();
break;
case 1: //bone orientation
q0 = new Quaternion(aseq.EvaluateVector(f0));
q1 = new Quaternion(aseq.EvaluateVector(f1));
q0 = aseq.EvaluateQuaternion(f0);
q1 = aseq.EvaluateQuaternion(f1);
q = interpolate ? Quaternion.Slerp(q0, q1, falpha) : q0;
bone.AnimRotation = q;
break;
@ -548,8 +548,6 @@ namespace CodeWalker.Rendering
bone.AnimScale = v.XYZ();
break;
case 5://root motion vector
if (bone.Tag != 0)
{ }
if (EnableRootMotion)
{
v0 = aseq.EvaluateVector(f0);
@ -558,13 +556,14 @@ namespace CodeWalker.Rendering
bone.AnimTranslation += v.XYZ();
}
break;
case 6://quaternion... root rotation?
if (bone.Tag != 0)
{ }
//q0 = new Quaternion(aseq.EvaluateVector(f0));
//q1 = new Quaternion(aseq.EvaluateVector(f1));
//q = interpolate ? Quaternion.Slerp(q0, q1, falpha) : q0;
//bone.AnimRotation *= q;
case 6://quaternion... root rotation
if (EnableRootMotion)
{
q0 = aseq.EvaluateQuaternion(f0);
q1 = aseq.EvaluateQuaternion(f1);
q = interpolate ? Quaternion.Slerp(q0, q1, falpha) : q0;
bone.AnimRotation = q * bone.AnimRotation;
}
break;
case 7://vector3... (camera position?)
break;