From 493e5da2e65946c7092e26acc154e12ca616903d Mon Sep 17 00:00:00 2001 From: Scobalula Date: Mon, 6 Apr 2020 13:03:11 +0100 Subject: [PATCH] Resident Evil 3 Support --- .../AssetHandlers/MaterialDefs.cs | 66 ++- src/Tyrant.Logic/AssetHandlers/Motion.cs | 466 +++++++++++++++++- src/Tyrant.Logic/AssetHandlers/MotionList.cs | 10 +- src/Tyrant/Windows/MainWindow.xaml.cs | 11 +- 4 files changed, 515 insertions(+), 38 deletions(-) diff --git a/src/Tyrant.Logic/AssetHandlers/MaterialDefs.cs b/src/Tyrant.Logic/AssetHandlers/MaterialDefs.cs index bf8cfd7..5b2a881 100644 --- a/src/Tyrant.Logic/AssetHandlers/MaterialDefs.cs +++ b/src/Tyrant.Logic/AssetHandlers/MaterialDefs.cs @@ -81,6 +81,19 @@ namespace Tyrant.Logic public long TextureNamePointer; } + /// + /// Resident Evil 7 Material Texture Entry + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct MaterialTextureEntryRE3 + { + public long TypePointer; + public uint TypeHash; + public uint UnkHash; + public long TextureNamePointer; + public long Padding; + } + /// /// Resident Evil 7 Material Texture Entry /// @@ -153,32 +166,59 @@ namespace Tyrant.Logic /// /// Converts the given material file /// - public static Dictionary Convert(byte[] buffer) + public static Dictionary ConvertRE3(BinaryReader reader) + { + var results = new Dictionary(); + + { + reader.BaseStream.Position = 0; + var header = reader.ReadStruct(); + var materials = reader.ReadArray(header.MaterialCount); + + Console.WriteLine(Marshal.SizeOf()); + + foreach (var material in materials) + { + var result = new Model.Material(reader.ReadUTF16NullTerminatedString(material.NamePointer)); + + foreach (var texture in reader.ReadArray(material.TexturesPointer, material.TextureCount)) + result.Images[reader.ReadUTF16NullTerminatedString(texture.TypePointer)] = reader.ReadUTF16NullTerminatedString(texture.TextureNamePointer).ToLower(); + //foreach (var setting in reader.ReadArray(material.SettingsInfoPointer, material.SettingsInfoCount)) + // result.Settings[reader.ReadUTF16NullTerminatedString(setting.NamePointer)] = reader.ReadArray(material.SettingsBufferPointer + setting.DataOffset, setting.DataCount); + + results[result.Name] = result; + } + } + + return results; + } + + /// + /// Converts the given material file + /// + public static Dictionary Convert(byte[] buffer, string gameName = "13") { using (var stream = new MemoryStream(buffer)) { - return Convert(stream); + return Convert(stream, gameName); } } /// /// Converts the given material file /// - public static Dictionary Convert(Stream stream) + public static Dictionary 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(); } } } diff --git a/src/Tyrant.Logic/AssetHandlers/Motion.cs b/src/Tyrant.Logic/AssetHandlers/Motion.cs index f3e4a27..c35c9b8 100644 --- a/src/Tyrant.Logic/AssetHandlers/Motion.cs +++ b/src/Tyrant.Logic/AssetHandlers/Motion.cs @@ -150,6 +150,18 @@ namespace Tyrant.Logic public long KeysPointer; } + /// + /// Resident Evil 3 Bone Data + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct BoneDataRE3 + { + public ushort BoneIndex; + public DataPrecenseFlags Flags; + public uint BoneHash; // MurMur3; + public int KeysPointer; + } + /// /// Resident Evil 7 Key Data (per channel per bone) /// @@ -165,6 +177,19 @@ namespace Tyrant.Logic public long UnpackDataPointer; } + /// + /// Resident Evil 3 Key Data (per channel per bone) + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct KeyDataRE3 + { + public uint Flags; + public int KeyCount; + public int FramesPointer; + public int DataPointer; + public int UnpackDataPointer; + } + /// /// Packed 16-Bit Vector 3 /// @@ -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 }, }; + /// + /// Vector 3 Decompressors, used by Translations and Scales for RE3 + /// + 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 }, + }; + /// /// Quaternion Decompressors, used by Rotations /// @@ -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 }, + }; + + /// + /// Quaternion Decompressors, used by Rotations + /// + 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 }, }; /// @@ -231,7 +308,7 @@ namespace Tyrant.Logic /// /// Loads 5Bit Vector3s /// - 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(dataPointer, frames.Length); @@ -245,18 +322,52 @@ namespace Tyrant.Logic } } + /// + /// Loads 5Bit Vector3s + /// + private static void LoadVector3s5BitB(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer) + { + var data = reader.ReadArray(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); + } + } + /// /// Loads 10Bit Vector3s /// - 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(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); + } + } + + /// + /// Loads 10Bit Vector3s + /// + private static void LoadVector3s10BitB(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer) + { + var data = reader.ReadArray(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 /// /// Loads 21Bit Vector3s /// - 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(dataPointer, frames.Length); @@ -279,6 +390,23 @@ namespace Tyrant.Logic } } + /// + /// Loads 21Bit Vector3s + /// + private static void LoadVector3s21BitB(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer) + { + var data = reader.ReadArray(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); + } + } + /// /// Loads Vector3s with 1 Component on X Axis /// @@ -330,6 +458,23 @@ namespace Tyrant.Logic } } + /// + /// Loads Vector3s with 1 Component on Z Axis + /// + private static void LoadVector3sXYZAxis(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer) + { + var data = reader.ReadArray(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); + } + } + /// /// Loads Vector3s with 1 Component on X Axis /// @@ -381,6 +526,25 @@ namespace Tyrant.Logic } } + /// + /// Loads Vector3s with 1 Component on Y Axis + /// + private static void LoadVector3sXYZAxis16Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer) + { + var data = reader.ReadArray(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); + } + } + /// /// Loads Quaternions with all components /// @@ -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); } } + /// + /// Loads 10Bit Quaternions + /// + private static void LoadQuaternions5Bit(BinaryReader reader, Animation.Bone bone, int[] frames, float[] unpackData, long dataPointer) + { + var data = reader.ReadArray(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); + } + } + + /// + /// Loads 10Bit Quaternions + /// + 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); + } + } + /// /// Loads 10Bit Quaternions /// @@ -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); + } + } + + /// + /// Loads 10Bit Quaternions + /// + 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); + } + } + + /// + /// Loads 18Bit Quaternions + /// + 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 /// 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(reader.ReadUTF16NullTerminatedString(header.NamePointer), animation); } + /// + /// Converts an RE3 Motion File to a SEAnim + /// + private static Tuple ConvertRE3(BinaryReader reader, Dictionary bones) + { + var animation = new Animation(Animation.DataType.Absolute); + + var header = reader.ReadStruct(); + + var name = reader.ReadUTF16NullTerminatedString(header.NamePointer); + + var localBones = new Dictionary(); + + { + if(bones.Count <= 0) + { + reader.BaseStream.Position = header.BoneBaseDataPointer; + + var baseDataOffset = reader.ReadInt64(); + var baseDataCount = reader.ReadInt32(); + + var boneBaseData = reader.ReadArray(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(header.BoneDataPointer, header.BoneDataCount); + + foreach (var bone in boneData) + { + var keyDataOffset = bone.KeysPointer; + + if (bone.Flags.HasFlag(DataPrecenseFlags.Translations)) + { + var keyData = reader.ReadStruct(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(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(); + } + + if (bone.Flags.HasFlag(DataPrecenseFlags.Rotations)) + { + var keyData = reader.ReadStruct(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(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(); + } + } + } + + foreach (var bone in localBones) + animation.Bones.Add(bone.Value); + } + + return new Tuple(reader.ReadUTF16NullTerminatedString(header.NamePointer), animation); + } + /// /// Converts the given Motion /// - public static Tuple Convert(Stream stream) + public static Tuple Convert(Stream stream, Dictionary 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"); } } diff --git a/src/Tyrant.Logic/AssetHandlers/MotionList.cs b/src/Tyrant.Logic/AssetHandlers/MotionList.cs index 72db47f..cd64722 100644 --- a/src/Tyrant.Logic/AssetHandlers/MotionList.cs +++ b/src/Tyrant.Logic/AssetHandlers/MotionList.cs @@ -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(); var results = new List>(); + var bones = new Dictionary(); // 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(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"); } } diff --git a/src/Tyrant/Windows/MainWindow.xaml.cs b/src/Tyrant/Windows/MainWindow.xaml.cs index 5b111fa..abbe563 100644 --- a/src/Tyrant/Windows/MainWindow.xaml.cs +++ b/src/Tyrant/Windows/MainWindow.xaml.cs @@ -70,6 +70,8 @@ namespace Tyrant { "natives/x64/streaming/", "natives/x64/", + "natives/stm/streaming/", + "natives/stm/", }; /// @@ -81,9 +83,12 @@ namespace Tyrant "_mat.mdf2.10", ".mdf2.6", "_mat.mdf2.6", + ".mdf2.13", + "_mat.mdf2.13", ".10", ".11", ".8", + ".190820018" }; /// @@ -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"); } }