using System.Collections.Generic; using System; using System.Runtime.InteropServices; public class PmgFile { [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 1)] public class PmgBlock { [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Vertex { public short height; // height sample public short lighting; // <= 255 } [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Tile { [Flags] public enum Transform : byte { FlipX = 1, Rotate90 = 2, Rotate180 = 4 } public enum Slip : byte { Full = 0, Bottom = 1, Left = 2, Top = 3, Right = 4, BottomRight = 5, BottomLeft = 6, TopLeft = 7, TopRight = 8 } public short Field0; // always 0 -> obsolete xOffset? public short Field1; // always 0 -> obsolete yOffset? public short Field2; // always 0 -> obsolete zOffset? public char Type; public Slip slip; public short Field3; public Transform RotationFlip; public int TextureIndex; public char Field4; } public short xOffset; // -16384 ~ 16384 public short yOffset; // unreliable? public short zOffset; // -16384 ~ 16384 public short Field0; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)] public Vertex[] vertices; public int Field1; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public Tile[] tiles; } public PmgBlock[] Blocks; public static PmgFile Parse(byte[] data) { PmgFile result = new PmgFile(); var blockSize = Marshal.SizeOf(typeof(PmgBlock)); int blockCount = data.Length / blockSize; var handle = GCHandle.Alloc(data, GCHandleType.Pinned); var ptr = handle.AddrOfPinnedObject(); List blocks = new List(); for (int Block = 0; Block < blockCount; Block++) { blocks.Add(Marshal.PtrToStructure(ptr)); ptr += blockSize; } handle.Free(); result.Blocks = blocks.ToArray(); return result; } }