mysimulation/server/tso.files/Formats/IFF/Chunks/ARRY.cs
Tony Bark 8fec258215 Added FSO.Files for use with the API server
Don't ask me. FreeSO is the prime example of dependency hell.
2024-05-01 04:38:12 -04:00

142 lines
4.8 KiB
C#
Executable file

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<flre; i++)
{
if (!io.HasMore) return;
Data[currentPosition++] = io.ReadByte();
if (currentPosition > 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)"
}
}