Resident Evil 3 Support

This commit is contained in:
Scobalula 2020-04-06 13:03:11 +01:00
parent 38dae7b9f2
commit 493e5da2e6
4 changed files with 515 additions and 38 deletions

View file

@ -81,6 +81,19 @@ namespace Tyrant.Logic
public long TextureNamePointer;
}
/// <summary>
/// Resident Evil 7 Material Texture Entry
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct MaterialTextureEntryRE3
{
public long TypePointer;
public uint TypeHash;
public uint UnkHash;
public long TextureNamePointer;
public long Padding;
}
/// <summary>
/// Resident Evil 7 Material Texture Entry
/// </summary>
@ -153,32 +166,59 @@ namespace Tyrant.Logic
/// <summary>
/// Converts the given material file
/// </summary>
public static Dictionary<string, Model.Material> Convert(byte[] buffer)
public static Dictionary<string, Model.Material> ConvertRE3(BinaryReader reader)
{
var results = new Dictionary<string, Model.Material>();
{
reader.BaseStream.Position = 0;
var header = reader.ReadStruct<MaterialHeaderRE7>();
var materials = reader.ReadArray<MaterialEntryRE2>(header.MaterialCount);
Console.WriteLine(Marshal.SizeOf<MaterialEntryRE2>());
foreach (var material in materials)
{
var result = new Model.Material(reader.ReadUTF16NullTerminatedString(material.NamePointer));
foreach (var texture in reader.ReadArray<MaterialTextureEntryRE3>(material.TexturesPointer, material.TextureCount))
result.Images[reader.ReadUTF16NullTerminatedString(texture.TypePointer)] = reader.ReadUTF16NullTerminatedString(texture.TextureNamePointer).ToLower();
//foreach (var setting in reader.ReadArray<MaterialSettingsInfoRE7>(material.SettingsInfoPointer, material.SettingsInfoCount))
// result.Settings[reader.ReadUTF16NullTerminatedString(setting.NamePointer)] = reader.ReadArray<float>(material.SettingsBufferPointer + setting.DataOffset, setting.DataCount);
results[result.Name] = result;
}
}
return results;
}
/// <summary>
/// Converts the given material file
/// </summary>
public static Dictionary<string, Model.Material> Convert(byte[] buffer, string gameName = "13")
{
using (var stream = new MemoryStream(buffer))
{
return Convert(stream);
return Convert(stream, gameName);
}
}
/// <summary>
/// Converts the given material file
/// </summary>
public static Dictionary<string, Model.Material> Convert(Stream stream)
public static Dictionary<string, Model.Material> Convert(Stream stream, string gameName = "13")
{
using (var reader = new BinaryReader(stream))
{
reader.BaseStream.Position = 28;
switch(gameName)
{
case "6": return ConvertRE7(reader);
case "10": return ConvertRE2(reader);
case "13": return ConvertRE3(reader);
}
// Check size of buffer
if(reader.ReadUInt32() != 0)
{
return ConvertRE2(reader);
}
else
{
return ConvertRE7(reader);
}
throw new Exception();
}
}
}

View file

@ -150,6 +150,18 @@ namespace Tyrant.Logic
public long KeysPointer;
}
/// <summary>
/// Resident Evil 3 Bone Data
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct BoneDataRE3
{
public ushort BoneIndex;
public DataPrecenseFlags Flags;
public uint BoneHash; // MurMur3;
public int KeysPointer;
}
/// <summary>
/// Resident Evil 7 Key Data (per channel per bone)
/// </summary>
@ -165,6 +177,19 @@ namespace Tyrant.Logic
public long UnpackDataPointer;
}
/// <summary>
/// Resident Evil 3 Key Data (per channel per bone)
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct KeyDataRE3
{
public uint Flags;
public int KeyCount;
public int FramesPointer;
public int DataPointer;
public int UnpackDataPointer;
}
/// <summary>
/// Packed 16-Bit Vector 3
/// </summary>
@ -182,9 +207,10 @@ namespace Tyrant.Logic
private static DataDecompressorList Vector3Decompressors = new DataDecompressorList()
{
{ 0x00000, LoadVector3sFull },
{ 0x20000, LoadVector3s5Bit },
{ 0x30000, LoadVector3s10Bit },
{ 0x70000, LoadVector3s21Bit },
{ 0x20000, LoadVector3s5BitA },
{ 0x30000, LoadVector3s10BitA },
{ 0x40000, LoadVector3s10BitA },
{ 0x70000, LoadVector3s21BitA },
{ 0x31000, LoadVector3sXAxis },
{ 0x32000, LoadVector3sYAxis },
{ 0x33000, LoadVector3sZAxis },
@ -193,6 +219,26 @@ namespace Tyrant.Logic
{ 0x23000, LoadVector3sZAxis16Bit },
};
/// <summary>
/// Vector 3 Decompressors, used by Translations and Scales for RE3
/// </summary>
private static DataDecompressorList Vector3DecompressorsRE3 = new DataDecompressorList()
{
{ 0x00000, LoadVector3sFull },
{ 0x20000, LoadVector3s5BitB },
{ 0x30000, LoadVector3s5BitB },
{ 0x40000, LoadVector3s10BitB },
{ 0x80000, LoadVector3s21BitB },
{ 0x21000, LoadVector3sXAxis16Bit },
{ 0x22000, LoadVector3sYAxis16Bit },
{ 0x23000, LoadVector3sZAxis16Bit },
{ 0x24000, LoadVector3sXYZAxis16Bit },
{ 0x41000, LoadVector3sXAxis },
{ 0x42000, LoadVector3sYAxis },
{ 0x43000, LoadVector3sZAxis },
{ 0x44000, LoadVector3sXYZAxis },
};
/// <summary>
/// Quaternion Decompressors, used by Rotations
/// </summary>
@ -200,15 +246,46 @@ namespace Tyrant.Logic
{
{ 0x00000, LoadQuaternionsFull },
{ 0xB0000, LoadQuaternions3Component },
{ 0xC0000, LoadQuaternions3Component },
{ 0x30000, LoadQuaternions10Bit },
{ 0x40000, LoadQuaternions10Bit },
{ 0x50000, LoadQuaternions16Bit },
{ 0x70000, LoadQuaternions21Bit },
{ 0x21000, LoadQuaternionsXAxis16Bit },
{ 0x22000, LoadQuaternionsYAxis16Bit },
{ 0x23000, LoadQuaternionsZAxis16Bit },
{ 0x31000, LoadQuaternionsXAxis },
{ 0x41000, LoadQuaternionsXAxis },
{ 0x32000, LoadQuaternionsYAxis },
{ 0x42000, LoadQuaternionsYAxis },
{ 0x33000, LoadQuaternionsZAxis },
{ 0x43000, LoadQuaternionsZAxis },
};
/// <summary>
/// Quaternion Decompressors, used by Rotations
/// </summary>
private static DataDecompressorList QuaternionDecompressorsRE3 = new DataDecompressorList()
{
{ 0x00000, LoadQuaternionsFull },
{ 0xB0000, LoadQuaternions3Component },
{ 0xC0000, LoadQuaternions3Component },
{ 0x20000, LoadQuaternions5Bit },
{ 0x30000, LoadQuaternions8Bit },
{ 0x40000, LoadQuaternions10Bit },
{ 0x50000, LoadQuaternions13Bit },
{ 0x60000, LoadQuaternions16Bit },
{ 0x70000, LoadQuaternions18Bit },
{ 0x80000, LoadQuaternions21Bit },
{ 0x21000, LoadQuaternionsXAxis16Bit },
{ 0x22000, LoadQuaternionsYAxis16Bit },
{ 0x23000, LoadQuaternionsZAxis16Bit },
{ 0x31000, LoadQuaternionsXAxis },
{ 0x41000, LoadQuaternionsXAxis },
{ 0x32000, LoadQuaternionsYAxis },
{ 0x42000, LoadQuaternionsYAxis },
{ 0x33000, LoadQuaternionsZAxis },
{ 0x43000, LoadQuaternionsZAxis },
};
/// <summary>
@ -231,7 +308,7 @@ namespace Tyrant.Logic
/// <summary>
/// Loads 5Bit Vector3s
/// </summary>
private static void LoadVector3s5Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
private static void LoadVector3s5BitA(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<ushort>(dataPointer, frames.Length);
@ -245,18 +322,52 @@ namespace Tyrant.Logic
}
}
/// <summary>
/// Loads 5Bit Vector3s
/// </summary>
private static void LoadVector3s5BitB(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<ushort>(dataPointer, frames.Length);
for (int i = 0; i < data.Length; i++)
{
var x = (unpackData[0] * ((data[i] >> 00) & 0x1F) / 31.0f) + unpackData[3];
var y = (unpackData[1] * ((data[i] >> 05) & 0x1F) / 31.0f) + unpackData[4];
var z = (unpackData[2] * ((data[i] >> 10) & 0x1F) / 31.0f) + unpackData[5];
bone.Translations[frames[i]] = new Vector3(x, y, z);
}
}
/// <summary>
/// Loads 10Bit Vector3s
/// </summary>
private static void LoadVector3s10Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
private static void LoadVector3s10BitA(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<uint>(dataPointer, frames.Length);
for (int i = 0; i < data.Length; i++)
{
var x = (unpackData[0] * ((data[i] >> 00) & 0x3FF) / 1023.0f) + unpackData[4];
var y = (unpackData[1] * ((data[i] >> 10) & 0x3FF) / 1023.0f) + unpackData[5];
var z = (unpackData[2] * ((data[i] >> 20) & 0x3FF) / 1023.0f) + unpackData[6];
var x = unpackData[0] * (((data[i] >> 00) & 0x3FF) * (1.0f / 0x3FF)) + unpackData[4];
var y = unpackData[1] * (((data[i] >> 10) & 0x3FF) * (1.0f / 0x3FF)) + unpackData[5];
var z = unpackData[2] * (((data[i] >> 20) & 0x3FF) * (1.0f / 0x3FF)) + unpackData[6];
bone.Translations[frames[i]] = new Vector3(x, y, z);
}
}
/// <summary>
/// Loads 10Bit Vector3s
/// </summary>
private static void LoadVector3s10BitB(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<uint>(dataPointer, frames.Length);
for (int i = 0; i < data.Length; i++)
{
var x = unpackData[0] * (((data[i] >> 00) & 0x3FF) * (1.0f / 0x3FF)) + unpackData[3];
var y = unpackData[1] * (((data[i] >> 10) & 0x3FF) * (1.0f / 0x3FF)) + unpackData[4];
var z = unpackData[2] * (((data[i] >> 20) & 0x3FF) * (1.0f / 0x3FF)) + unpackData[5];
bone.Translations[frames[i]] = new Vector3(x, y, z);
}
@ -265,7 +376,7 @@ namespace Tyrant.Logic
/// <summary>
/// Loads 21Bit Vector3s
/// </summary>
private static void LoadVector3s21Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
private static void LoadVector3s21BitA(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<ulong>(dataPointer, frames.Length);
@ -279,6 +390,23 @@ namespace Tyrant.Logic
}
}
/// <summary>
/// Loads 21Bit Vector3s
/// </summary>
private static void LoadVector3s21BitB(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<ulong>(dataPointer, frames.Length);
for (int i = 0; i < data.Length; i++)
{
var x = (unpackData[0] * ((data[i] >> 00) & 0x1FFFFF) / 2097151.0f) + unpackData[3];
var y = (unpackData[1] * ((data[i] >> 21) & 0x1FFFFF) / 2097151.0f) + unpackData[4];
var z = (unpackData[2] * ((data[i] >> 42) & 0x1FFFFF) / 2097151.0f) + unpackData[5];
bone.Translations[frames[i]] = new Vector3(x, y, z);
}
}
/// <summary>
/// Loads Vector3s with 1 Component on X Axis
/// </summary>
@ -330,6 +458,23 @@ namespace Tyrant.Logic
}
}
/// <summary>
/// Loads Vector3s with 1 Component on Z Axis
/// </summary>
private static void LoadVector3sXYZAxis(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<float>(dataPointer, frames.Length);
for (int i = 0; i < data.Length; i++)
{
var x = data[i];
var y = data[i];
var z = data[i];
bone.Translations[frames[i]] = new Vector3(x, y, z);
}
}
/// <summary>
/// Loads Vector3s with 1 Component on X Axis
/// </summary>
@ -381,6 +526,25 @@ namespace Tyrant.Logic
}
}
/// <summary>
/// Loads Vector3s with 1 Component on Y Axis
/// </summary>
private static void LoadVector3sXYZAxis16Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<ushort>(dataPointer, frames.Length);
for (int i = 0; i < data.Length; i++)
{
var val = unpackData[0] * (data[i] / 65535.0f) + unpackData[3];
var x = val;
var y = val;
var z = val;
bone.Translations[frames[i]] = new Vector3(x, y, z);
}
}
/// <summary>
/// Loads Quaternions with all components
/// </summary>
@ -412,13 +576,64 @@ namespace Tyrant.Logic
var x = data[i].X;
var y = data[i].Y;
var z = data[i].Z;
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
}
/// <summary>
/// Loads 10Bit Quaternions
/// </summary>
private static void LoadQuaternions5Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
var data = reader.ReadArray<ushort>(dataPointer, frames.Length);
for (int i = 0; i < data.Length; i++)
{
var x = (unpackData[0] * ((data[i] >> 00) & 0x1F) * (1.0f / 0x1F)) + unpackData[4];
var y = (unpackData[1] * ((data[i] >> 05) & 0x1F) * (1.0f / 0x1F)) + unpackData[5];
var z = (unpackData[2] * ((data[i] >> 10) & 0x1F) * (1.0f / 0x1F)) + unpackData[6];
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
}
/// <summary>
/// Loads 10Bit Quaternions
/// </summary>
private static void LoadQuaternions8Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
reader.BaseStream.Position = dataPointer;
for (int i = 0; i < frames.Length; i++)
{
var x = (unpackData[0] * (reader.ReadByte() * 0.000015259022f)) + unpackData[4];
var y = (unpackData[1] * (reader.ReadByte() * 0.000015259022f)) + unpackData[5];
var z = (unpackData[2] * (reader.ReadByte() * 0.000015259022f)) + unpackData[6];
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
}
/// <summary>
/// Loads 10Bit Quaternions
/// </summary>
@ -431,7 +646,12 @@ namespace Tyrant.Logic
var x = (unpackData[0] * ((data[i] >> 00) & 0x3FF) / 1023.0f) + unpackData[4];
var y = (unpackData[1] * ((data[i] >> 10) & 0x3FF) / 1023.0f) + unpackData[5];
var z = (unpackData[2] * ((data[i] >> 20) & 0x3FF) / 1023.0f) + unpackData[6];
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -449,7 +669,61 @@ namespace Tyrant.Logic
var x = (unpackData[0] * (data[i].X / 65535.0f)) + unpackData[4];
var y = (unpackData[1] * (data[i].Y / 65535.0f)) + unpackData[5];
var z = (unpackData[2] * (data[i].Z / 65535.0f)) + unpackData[6];
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = (float)Math.Sqrt(Math.Abs(1 - x * x - y * y - z * z));
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
}
/// <summary>
/// Loads 10Bit Quaternions
/// </summary>
private static void LoadQuaternions13Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
reader.BaseStream.Position = dataPointer;
for (int i = 0; i < frames.Length; i++)
{
var data = reader.ReadBytes(5);
ulong val = 0;
for(int j = 0; j < 5; j++)
val = data[j] | (val << 8);
var x = (unpackData[0] * ((val >> 00) & 0x1FFF) * 0.00012208521f) + unpackData[4];
var y = (unpackData[1] * ((val >> 13) & 0x1FFF) * 0.00012208521f) + unpackData[5];
var z = (unpackData[2] * ((val >> 26) & 0x1FFF) * 0.00012208521f) + unpackData[6];
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
}
/// <summary>
/// Loads 18Bit Quaternions
/// </summary>
private static void LoadQuaternions18Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer)
{
for (int i = 0; i < frames.Length; i++)
{
var data = reader.ReadBytes(7);
ulong val = 0;
for (int j = 0; j < 7; j++)
val = data[j] | (val << 8);
var x = (unpackData[0] * ((val >> 00) & 0x1FFF) * 0.00012208521f) + unpackData[4];
var y = (unpackData[1] * ((val >> 13) & 0x1FFF) * 0.00012208521f) + unpackData[5];
var z = (unpackData[2] * ((val >> 26) & 0x1FFF) * 0.00012208521f) + unpackData[6];
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -467,7 +741,12 @@ namespace Tyrant.Logic
var x = (unpackData[0] * ((data[i] >> 00) & 0x1FFFFF) / 2097151.0f) + unpackData[4];
var y = (unpackData[1] * ((data[i] >> 21) & 0x1FFFFF) / 2097151.0f) + unpackData[5];
var z = (unpackData[2] * ((data[i] >> 42) & 0x1FFFFF) / 2097151.0f) + unpackData[6];
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -485,7 +764,12 @@ namespace Tyrant.Logic
var x = data[i];
var y = 0.0f;
var z = 0.0f;
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -503,7 +787,12 @@ namespace Tyrant.Logic
var x = 0.0f;
var y = data[i];
var z = 0.0f;
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -521,7 +810,12 @@ namespace Tyrant.Logic
var x = 0.0f;
var y = 0.0f;
var z = data[i];
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -540,7 +834,12 @@ namespace Tyrant.Logic
var x = unpackData[0] * (data[i] / 65535.0f) + unpackData[1];
var y = 0.0f;
var z = 0.0f;
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -558,7 +857,12 @@ namespace Tyrant.Logic
var x = 0.0f;
var y = unpackData[0] * (data[i] / 65535.0f) + unpackData[1];
var z = 0.0f;
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -576,7 +880,12 @@ namespace Tyrant.Logic
var x = 0.0f;
var y = 0.0f;
var z = unpackData[0] * (data[i] / 65535.0f) + unpackData[1];
var w = (float)Math.Sqrt(1 - x * x - y * y - z * z);
var w = 1.0f - (x * x + y * y + z * z);
if (w > 0.0f)
w = (float)Math.Sqrt(w);
else
w = 0.0f;
bone.Rotations[frames[i]] = new Quaternion(x, y, z, w);
}
@ -587,6 +896,15 @@ namespace Tyrant.Logic
/// </summary>
private static int[] LoadFrames(BinaryReader reader, long framesPointer, int frameCount, uint frameDataType)
{
if(frameCount < 2)
{
return new int[]
{
0
};
}
var results = new int[frameCount];
reader.BaseStream.Position = framesPointer;
@ -698,6 +1016,7 @@ namespace Tyrant.Logic
var keyFrames = LoadFrames(reader, keyData.FramesPointer, keyData.KeyCount, keyFrameDataType);
if (QuaternionDecompressors.TryGetValue(compression, out var decompressionMethod))
decompressionMethod(reader, bones[bone.BoneHash], keyFrames, unpackData, keyData.DataPointer);
else
@ -808,10 +1127,116 @@ namespace Tyrant.Logic
return new Tuple<string, Animation>(reader.ReadUTF16NullTerminatedString(header.NamePointer), animation);
}
/// <summary>
/// Converts an RE3 Motion File to a SEAnim
/// </summary>
private static Tuple<string, Animation> ConvertRE3(BinaryReader reader, Dictionary<uint, Animation.Bone> bones)
{
var animation = new Animation(Animation.DataType.Absolute);
var header = reader.ReadStruct<MotionHeaderRE2>();
var name = reader.ReadUTF16NullTerminatedString(header.NamePointer);
var localBones = new Dictionary<uint, Animation.Bone>();
{
if(bones.Count <= 0)
{
reader.BaseStream.Position = header.BoneBaseDataPointer;
var baseDataOffset = reader.ReadInt64();
var baseDataCount = reader.ReadInt32();
var boneBaseData = reader.ReadArray<BoneBaseDataRE7>(baseDataOffset, baseDataCount);
foreach (var boneBase in boneBaseData)
{
var bone = new Animation.Bone(reader.ReadUTF16NullTerminatedString(boneBase.NamePointer));
bone.Translations[0] = boneBase.Translation.ToVector3();
bone.Rotations[0] = boneBase.Rotation;
bones[boneBase.Hash] = bone;
}
}
// Add base data
foreach(var bone in bones)
{
var nbone = new Animation.Bone(bone.Value.Name);
nbone.Translations[0] = bone.Value.Translations[0];
nbone.Rotations[0] = bone.Value.Rotations[0];
localBones[bone.Key] = nbone;
}
if (header.BoneDataPointer > 0)
{
var boneData = reader.ReadArray<BoneDataRE3>(header.BoneDataPointer, header.BoneDataCount);
foreach (var bone in boneData)
{
var keyDataOffset = bone.KeysPointer;
if (bone.Flags.HasFlag(DataPrecenseFlags.Translations))
{
var keyData = reader.ReadStruct<KeyDataRE3>(keyDataOffset);
float[] unpackData = null;
uint keyFrameDataType = keyData.Flags & 0xF00000;
uint compression = keyData.Flags & 0xFF000;
uint unkFlag = keyData.Flags & 0xFFF;
if (keyData.UnpackDataPointer > 0)
unpackData = reader.ReadArray<float>(keyData.UnpackDataPointer, 16);
var keyFrames = LoadFrames(reader, keyData.FramesPointer, keyData.KeyCount, keyFrameDataType);
if (Vector3DecompressorsRE3.TryGetValue(compression, out var decompressionMethod))
decompressionMethod(reader, localBones[bone.BoneHash], keyFrames, unpackData, keyData.DataPointer);
else
throw new Exception(string.Format("Unknown Vector3 compression type: 0x{0:X}", compression));
keyDataOffset += Marshal.SizeOf<KeyDataRE3>();
}
if (bone.Flags.HasFlag(DataPrecenseFlags.Rotations))
{
var keyData = reader.ReadStruct<KeyDataRE3>(keyDataOffset);
float[] unpackData = null;
uint keyFrameDataType = keyData.Flags & 0xF00000;
uint compression = keyData.Flags & 0xFF000;
uint unkFlag = keyData.Flags & 0xFFF;
if (keyData.UnpackDataPointer > 0)
unpackData = reader.ReadArray<float>(keyData.UnpackDataPointer, 16);
var keyFrames = LoadFrames(reader, keyData.FramesPointer, keyData.KeyCount, keyFrameDataType);
if (QuaternionDecompressorsRE3.TryGetValue(compression, out var decompressionMethod))
decompressionMethod(reader, localBones[bone.BoneHash], keyFrames, unpackData, keyData.DataPointer);
else
throw new Exception(string.Format("Unknown Quaternion compression type: 0x{0:X}", compression));
keyDataOffset += Marshal.SizeOf<KeyDataRE3>();
}
}
}
foreach (var bone in localBones)
animation.Bones.Add(bone.Value);
}
return new Tuple<string, Animation>(reader.ReadUTF16NullTerminatedString(header.NamePointer), animation);
}
/// <summary>
/// Converts the given Motion
/// </summary>
public static Tuple<string, Animation> Convert(Stream stream)
public static Tuple<string, Animation> Convert(Stream stream, Dictionary<uint, Animation.Bone> bones)
{
using (var reader = new BinaryReader(stream))
{
@ -822,6 +1247,7 @@ namespace Tyrant.Logic
{
case 0x2B: return ConvertRE7(reader);
case 0x41: return ConvertRE2(reader);
case 0x4E: return ConvertRE3(reader, bones);
default: throw new Exception("Invalid Motion Version");
}
}

View file

@ -89,7 +89,7 @@ namespace Tyrant.Logic
using (var stream = new MemoryStream(reader.ReadBytes((int)(endOffset - offsets[i]))))
{
results.Add(Motion.Convert(stream));
results.Add(Motion.Convert(stream, null));
}
}
@ -103,6 +103,7 @@ namespace Tyrant.Logic
{
var header = reader.ReadStruct<MotionListHeaderRE2>();
var results = new List<Tuple<string, Animation>>();
var bones = new Dictionary<uint, Animation.Bone>();
// Sort by offsets since they don't store sizes, we also need to remove dupes as some entries point to another
var offsets = reader.ReadArray<long>(header.AssetsPointer, header.AssetCount).Distinct().OrderBy(x => x).ToArray();
@ -122,9 +123,11 @@ namespace Tyrant.Logic
reader.BaseStream.Position = offsets[i];
using (var stream = new MemoryStream(reader.ReadBytes((int)(endOffset - offsets[i]))))
var buffer = reader.ReadBytes((int)(endOffset - offsets[i]));
using (var stream = new MemoryStream(buffer))
{
results.Add(Motion.Convert(stream));
results.Add(Motion.Convert(stream, bones));
}
}
@ -154,6 +157,7 @@ namespace Tyrant.Logic
{
case 0x3C: return ConvertRE7(reader);
case 0x55: return ConvertRE2(reader);
case 0x63: return ConvertRE2(reader);
default: throw new Exception("Invalid Motion List Version");
}
}

View file

@ -70,6 +70,8 @@ namespace Tyrant
{
"natives/x64/streaming/",
"natives/x64/",
"natives/stm/streaming/",
"natives/stm/",
};
/// <summary>
@ -81,9 +83,12 @@ namespace Tyrant
"_mat.mdf2.10",
".mdf2.6",
"_mat.mdf2.6",
".mdf2.13",
"_mat.mdf2.13",
".10",
".11",
".8",
".190820018"
};
/// <summary>
@ -278,7 +283,6 @@ namespace Tyrant
var folder = Path.Combine(path, motions.Item1);
var result = path;
Directory.CreateDirectory(folder);
foreach(var motion in motions.Item2)
@ -390,7 +394,7 @@ namespace Tyrant
{
try
{
materials = MaterialDefs.Convert(ActivePackage.LoadEntry(result));
materials = MaterialDefs.Convert(ActivePackage.LoadEntry(result), prefix.Split('.').Last());
break;
}
catch
@ -487,6 +491,9 @@ namespace Tyrant
}
catch (Exception e)
{
#if DEBUG
File.WriteAllBytes("BAD_BUFFER.dat", ActivePackage.LoadEntry(asset.PackageEntry));
#endif
Log(string.Format("Error has occured while exporting {0}: {1}", Path.GetFileNameWithoutExtension(asset.Name), e), "ERROR");
}
}