diff --git a/Source/SharpNeedle/HedgehogEngine/Mirage/Mesh.cs b/Source/SharpNeedle/HedgehogEngine/Mirage/Mesh.cs index 655719e..b01930d 100644 --- a/Source/SharpNeedle/HedgehogEngine/Mirage/Mesh.cs +++ b/Source/SharpNeedle/HedgehogEngine/Mirage/Mesh.cs @@ -1,19 +1,19 @@ namespace SharpNeedle.HedgehogEngine.Mirage; using System.IO; -public class Mesh : IBinarySerializable, IDisposable, ICloneable +public class Mesh : IBinarySerializable, IDisposable, ICloneable { public ResourceReference Material { get; set; } public ushort[] Faces { get; set; } public uint VertexSize { get; set; } public uint VertexCount { get; set; } public byte[] Vertices { get; set; } - public byte[] BoneIndices { get; set; } + public short[] BoneIndices { get; set; } public List Elements { get; set; } public List Textures { get; set; } public MeshSlot Slot { get; set; } - public void Read(BinaryObjectReader reader) + public void Read(BinaryObjectReader reader, uint version) { Elements ??= new List(); Material = reader.ReadStringOffset(); @@ -36,12 +36,16 @@ public void Read(BinaryObjectReader reader) } }); - BoneIndices = reader.ReadArrayOffset(reader.Read()); + if(version >= 6) + BoneIndices = reader.ReadArrayOffset(reader.Read()); + else + BoneIndices = reader.ReadArrayOffset(reader.Read()).Select(Convert.ToInt16).ToArray(); + Textures = reader.ReadObject>>().Unwind(); SwapVertexEndianness(); } - public void Write(BinaryObjectWriter writer) + public void Write(BinaryObjectWriter writer, uint version) { writer.WriteStringOffset(StringBinaryFormat.NullTerminated, Path.GetFileNameWithoutExtension(Material.Name)); writer.Write(Faces.Length); @@ -69,7 +73,11 @@ public void Write(BinaryObjectWriter writer) }); writer.Write(BoneIndices.Length); - writer.WriteArrayOffset(BoneIndices); + + if(version >= 6) + writer.WriteArrayOffset(BoneIndices); + else + writer.WriteArrayOffset(BoneIndices.Select(Convert.ToByte).ToArray()); writer.Write(Textures.Count); writer.WriteOffset(() => diff --git a/Source/SharpNeedle/HedgehogEngine/Mirage/MeshGroup.cs b/Source/SharpNeedle/HedgehogEngine/Mirage/MeshGroup.cs index 5d42b93..6c19dd1 100644 --- a/Source/SharpNeedle/HedgehogEngine/Mirage/MeshGroup.cs +++ b/Source/SharpNeedle/HedgehogEngine/Mirage/MeshGroup.cs @@ -1,17 +1,16 @@ namespace SharpNeedle.HedgehogEngine.Mirage; -public class MeshGroup : List, IBinarySerializable, IDisposable, ICloneable +public class MeshGroup : List, IBinarySerializable, IDisposable, ICloneable { public string Name { get; set; } - public void Read(BinaryObjectReader reader) - => Read(reader, true); - - public void Read(BinaryObjectReader reader, bool readSpecial) + public void Read(BinaryObjectReader reader, uint version) { - var opaqMeshes = reader.ReadObject>>(); - var transMeshes = reader.ReadObject>>(); - var punchMeshes = reader.ReadObject>>(); + bool readSpecial = version >= 5; + + var opaqMeshes = reader.ReadObject, uint>, uint>(version); + var transMeshes = reader.ReadObject, uint>, uint>(version); + var punchMeshes = reader.ReadObject, uint>, uint>(version); Clear(); @@ -65,7 +64,7 @@ public void Read(BinaryObjectReader reader, bool readSpecial) Name = reader.ReadString(StringBinaryFormat.NullTerminated); - void AddMeshes(BinaryList> meshes, MeshSlot slot) + void AddMeshes(BinaryList, uint> meshes, MeshSlot slot) { foreach (var mesh in meshes) { @@ -75,11 +74,10 @@ void AddMeshes(BinaryList> meshes, MeshSlot slot) } } - public void Write(BinaryObjectWriter writer) - => Write(writer, true); - - public void Write(BinaryObjectWriter writer, bool writeSpecial) + public void Write(BinaryObjectWriter writer, uint version) { + bool writeSpecial = version >= 5; + WriteMeshes(this.Where(x => x.Slot == Mesh.Type.Opaque)); WriteMeshes(this.Where(x => x.Slot == Mesh.Type.Transparent)); WriteMeshes(this.Where(x => x.Slot == Mesh.Type.PunchThrough)); @@ -135,7 +133,7 @@ void WriteMeshes(IEnumerable meshes) writer.WriteOffset(() => { foreach (var mesh in meshes) - writer.WriteObjectOffset(mesh); + writer.WriteObjectOffset(mesh, version); }); } } diff --git a/Source/SharpNeedle/HedgehogEngine/Mirage/ModelBase.cs b/Source/SharpNeedle/HedgehogEngine/Mirage/ModelBase.cs index 53f0267..73c7897 100644 --- a/Source/SharpNeedle/HedgehogEngine/Mirage/ModelBase.cs +++ b/Source/SharpNeedle/HedgehogEngine/Mirage/ModelBase.cs @@ -23,13 +23,9 @@ protected override void Dispose(bool disposing) protected void CommonRead(BinaryObjectReader reader) { if (DataVersion >= 5) - Groups = reader.ReadObject>>().Unwind(); + Groups = reader.ReadObject, uint>, uint>(DataVersion).Unwind(); else - { - var group = new MeshGroup(); - group.Read(reader, false); - Groups = new List { group }; - } + Groups = new List { reader.ReadObject(DataVersion) }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -41,19 +37,19 @@ protected void CommonWrite(BinaryObjectWriter writer) writer.WriteOffset(() => { foreach (var group in Groups) - writer.WriteObjectOffset(group); + writer.WriteObjectOffset(group, DataVersion); }); } else { if (Groups.Count == 1) - Groups[0].Write(writer, false); + writer.WriteObject(Groups[0], DataVersion); else { var dummyMeshGroup = new MeshGroup(); dummyMeshGroup.Capacity = Groups.Sum(x => x.Count); dummyMeshGroup.AddRange(Groups.SelectMany(x => x)); - dummyMeshGroup.Write(writer, false); + writer.WriteObject(dummyMeshGroup, DataVersion); } } } diff --git a/Source/SharpNeedle/Utilities/BinaryHelper.cs b/Source/SharpNeedle/Utilities/BinaryHelper.cs index 0df2102..d541655 100644 --- a/Source/SharpNeedle/Utilities/BinaryHelper.cs +++ b/Source/SharpNeedle/Utilities/BinaryHelper.cs @@ -184,6 +184,15 @@ public static void WriteOffsetValue(this BinaryObjectWriter writer, long value) return result; } + public static List Unwind(this BinaryList, TContext> list) where T : IBinarySerializable, new() + { + var result = new List(list.Count); + foreach (var item in list) + result.Add(item); + + return result; + } + public static unsafe T* Pointer(this T[] data) where T : unmanaged { if (data == null || data.Length == 0) diff --git a/Source/SharpNeedle/Utilities/BinaryList.cs b/Source/SharpNeedle/Utilities/BinaryList.cs index 7c340c5..072e740 100644 --- a/Source/SharpNeedle/Utilities/BinaryList.cs +++ b/Source/SharpNeedle/Utilities/BinaryList.cs @@ -106,4 +106,113 @@ public T this[int index] public static implicit operator BinaryList(List items) => new(items); public static implicit operator List(BinaryList self) => self.Items; +} + +public struct BinaryList : IBinarySerializable, IList where T : IBinarySerializable, new() +{ + public List Items { get; set; } + public int Count => Items.Count; + public bool IsReadOnly => false; + + public BinaryList(List items) + { + Items = items; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(BinaryObjectReader reader, TContext context) + { + var count = reader.ReadOffsetValue(); + + // Use token because accessing `this` with lambda on structs is a nightmare + var offset = reader.ReadOffsetValue(); + if (offset == 0) + return; + + Items = new List((int)count); + using var token = reader.AtOffset(offset); + for (long i = 0; i < count; i++) + { + var obj = reader.ReadObject(context); + Items.Add(obj); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(BinaryObjectWriter writer, TContext context) + { + if (Items == null) + { + writer.WriteOffsetValue(0); + writer.WriteOffsetValue(0); + return; + } + + writer.WriteOffsetValue(Items.Count); + writer.WriteOffset(writer.DefaultAlignment, null, Items, (_, items) => + { + foreach (var item in (List)items) + writer.WriteObject(item, context); + }); + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)Items).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(T item) + { + Items.Add(item); + } + + public void Clear() + { + Items.Clear(); + } + + public bool Contains(T item) + { + return Items.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + Items.CopyTo(array, arrayIndex); + } + + public bool Remove(T item) + { + return Items.Remove(item); + } + + public int IndexOf(T item) + { + return Items.IndexOf(item); + } + + public void Insert(int index, T item) + { + Items.Insert(index, item); + } + + public void RemoveAt(int index) + { + Items.RemoveAt(index); + } + + public T this[int index] + { + get => Items[index]; + set => Items[index] = value; + } + + public static implicit operator BinaryList(List items) => new(items); + public static implicit operator List(BinaryList self) => self.Items; } \ No newline at end of file diff --git a/Source/SharpNeedle/Utilities/BinaryPointer.cs b/Source/SharpNeedle/Utilities/BinaryPointer.cs index e6d15df..7cb6c59 100644 --- a/Source/SharpNeedle/Utilities/BinaryPointer.cs +++ b/Source/SharpNeedle/Utilities/BinaryPointer.cs @@ -30,4 +30,36 @@ public void Write(BinaryObjectWriter writer) public static implicit operator T(BinaryPointer self) => self.Value; public static implicit operator BinaryPointer(T value) => new(value); +} + +public struct BinaryPointer : IBinarySerializable where T : IBinarySerializable, new() +{ + public T Value; + + public BinaryPointer(T value) + { + Value = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(BinaryObjectReader reader, TContext context) + { + var offset = reader.ReadOffsetValue(); + if (offset == 0) + return; + + Value = reader.ReadObjectAtOffset(offset, context); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(BinaryObjectWriter writer, TContext context) + { + if (Value is null) + writer.WriteOffsetValue(0); + else + writer.WriteObjectOffset(Value, context); + } + + public static implicit operator T(BinaryPointer self) => self.Value; + public static implicit operator BinaryPointer(T value) => new(value); } \ No newline at end of file