using FSO.Files.Utils; using System.IO; using System.Text; namespace FSO.Files.Formats.IFF.Chunks { public class ARRY : IffChunk { public int Width; public int Height; public ARRYType Type; public byte[] Data; public byte[] TransposeData { get { var stride = (int)Type; byte[] result = new byte[Data.Length]; for (int i = 0; i < Data.Length; i += stride) { var divI = i / stride; var x = divI % Width; var y = divI / Width; int targetIndex = y * stride + x * stride * Width; for (int j = 0; j < stride; j++) { result[targetIndex++] = Data[i + j]; } } return result; } } public override void Read(IffFile iff, Stream stream) { using (var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN)) { var zero = io.ReadInt32(); Width = io.ReadInt32(); Height = io.ReadInt32(); Type = (ARRYType)io.ReadInt32(); var dataByteSize = ByteSize(); Data = new byte[Width * Height * dataByteSize]; var unknown = io.ReadInt32(); int currentPosition = 0; while (io.HasMore) { switch (Type) { default: //bit format: //1000 yyyy yyxx xxxx var flre = io.ReadUInt16(); if (flre == 0) break; bool rawFill = (flre & 0x8000) == 0; if (rawFill) { for (int i=0; i Data.Length) return; } if ((flre & 1) == 1) io.ReadByte(); continue; } var lastPosition = currentPosition; currentPosition += flre & 0x7FFF; currentPosition %= Data.Length; //wrap to data size if (currentPosition == 0) return; var pad = io.ReadByte();//ReadElement(io); //pad the previous entries with this data //if ((dataByteSize & 1) == 1) io.ReadByte(); //padded to 16 bits while (lastPosition < currentPosition) { Data[lastPosition++] = pad; } if (!io.HasMore) return; var size = io.ReadInt16(); if ((size & 0x8000) != 0) { io.Seek(SeekOrigin.Current, -2); continue; } for (int i = 0; i < size; i++) { Data[currentPosition++] = io.ReadByte();//ReadElement(io); currentPosition %= Data.Length; } if ((size & 1) == 1) io.ReadByte(); //16-bit pad currentPosition %= Data.Length; //12 bit wrap break; } } } } public int ByteSize() { return (int)Type; } public string DebugPrint() { var dataByteSize = ByteSize(); var result = new StringBuilder(); int index = 0; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { var item = Data[index]; var str = item.ToString().PadLeft(3, ' '); result.Append((str == " 0") ? " ." : str); index += dataByteSize; } result.AppendLine(); } return result.ToString(); } } public enum ARRYType : int { RLEAlt = 4, //altitude RLEFloor = 1, //floors, "ground", grass, flags, pool "ARRY(9)", water RLEWalls = 8, //walls Objects = 2, //objects "ARRY(3)" } }