// As found in .DAT archives (RESOURCE.DAT, IO.DAT)
        public void Load(string destinationDirectory, string baseName, BinaryReader binaryReader)
        {
            xOffset = binaryReader.ReadInt16();
            yOffset = binaryReader.ReadInt16();
            binaryReader.BaseStream.Seek(4, SeekOrigin.Current);
            width = binaryReader.ReadUInt16();
            height = binaryReader.ReadUInt16();
            binaryReader.BaseStream.Seek(2, SeekOrigin.Current);
            uint length = binaryReader.ReadUInt32();

            var imageOffset = binaryReader.BaseStream.Position;

            var rowDataOffsets = new ushort[height];
            for (int i = 0; i < height; ++i) {
                rowDataOffsets[i] = binaryReader.ReadUInt16();
            }

            var bmp = new Bmp(width, height);
            var imageData = binaryReader.ReadBytes((int)length - 2*height);

            ReadImage(imageData, rowDataOffsets, false, bmp.Data);

            Debug.Assert(binaryReader.BaseStream.Position - imageOffset == length);
            bmp.Save(Path.Combine(destinationDirectory, baseName), ImageFormat);
            Bmp.SaveOffsets(baseName, xOffset, yOffset);
        }
        public void Load(string destinationDirectory, string resourceName, BinaryReader binaryReader)
        {
            binaryReader.BaseStream.Seek(2, SeekOrigin.Current);
            uint length = binaryReader.ReadUInt32();
            byte[] imageData = binaryReader.ReadBytes((int)length);
            short xOffset = binaryReader.ReadInt16();
            short yOffset = binaryReader.ReadInt16();
            ushort width = binaryReader.ReadUInt16();
            ushort height = binaryReader.ReadUInt16();
            binaryReader.BaseStream.Seek(8, SeekOrigin.Current);

            var bmp = new Bmp(width, height);
            var colorData = bmp.Data;
            var palette = PaletteLoader.DefaultPalette;
            int index = 0;
            for (int y = 0; y < height; ++y) {
                for (int x = 0; x < width; ++x) {
                    colorData[y, x] = palette.Colors[imageData[index]];
                    ++index;
                }
            }

            bmp.Save(Path.Combine(destinationDirectory, resourceName), ImageFormat);
            Bmp.SaveOffsets(resourceName, xOffset, yOffset);
        }
        public void Load(string destinationDirectory, string resourceName, BinaryReader binaryReader)
        {
            short xOffset = binaryReader.ReadInt16();
            short yOffset = binaryReader.ReadInt16();
            binaryReader.BaseStream.Seek(4, SeekOrigin.Current);
            ushort width = binaryReader.ReadUInt16();
            ushort height = binaryReader.ReadUInt16();
            binaryReader.BaseStream.Seek(2, SeekOrigin.Current);
            uint length = binaryReader.ReadUInt32();
            var start = binaryReader.BaseStream.Position;

            // Set to magenta for now (should be white ("gray" as RTTR calls it))
            var gray = new Rgba {
                R = byte.MaxValue,
                G = 0,//byte.MaxValue,
                B = byte.MaxValue,
                A = byte.MaxValue
            };
            var transparent = new Rgba {
                R = byte.MaxValue,
                G = byte.MaxValue,
                B = byte.MaxValue,
                A = 0
            };

            // Skip row indexes, not necessary
            binaryReader.BaseStream.Seek(2 * height, SeekOrigin.Current);
            var bmp = new Bmp(width, height);
            var palette = PaletteLoader.DefaultPalette;

            for (int y = 0; y < height; ++y) {
                int x = 0;
                while (x < width) {
                    byte count = binaryReader.ReadByte();
                    for (int i = 0; i < count; ++i) {
                        bmp.Data[y, x] = gray;
                        ++x;
                    }
                    count = binaryReader.ReadByte();
                    for (int i = 0; i < count; ++i) {
                        bmp.Data[y, x] = transparent;
                        ++x;
                    }
                }
                // Skip delimiter
                binaryReader.ReadByte();
            }

            binaryReader.BaseStream.Seek(start + length, SeekOrigin.Begin);
            bmp.Save(Path.Combine(destinationDirectory, resourceName), ImageFormat.Png);
            Bmp.SaveOffsets(resourceName, xOffset, yOffset);
        }
        public void Load(string destinationDirectory, string resourceName, BinaryReader binaryReader)
        {
            short xOffset = binaryReader.ReadInt16();
            short yOffset = binaryReader.ReadInt16();
            binaryReader.BaseStream.Seek(4, SeekOrigin.Current);
            ushort width = binaryReader.ReadUInt16();
            ushort height = binaryReader.ReadUInt16();
            binaryReader.BaseStream.Seek(2, SeekOrigin.Current);
            uint length = binaryReader.ReadUInt32();
            var start = binaryReader.BaseStream.Position;

            if (length <= 0) {
                return;
            }

            binaryReader.BaseStream.Seek(2 * height, SeekOrigin.Current);
            var bmp = new Bmp(width, height);
            var colorData = bmp.Data;
            var palette = PaletteLoader.DefaultPalette;

            for (int y = 0; y < height; ++y) {
                int x = 0;
                while (x < width) {
                    // color pixels
                    byte count = binaryReader.ReadByte();
                    for (int i = 0; i < count; ++i) {
                        colorData[y, x] = palette.Colors[binaryReader.ReadByte()];
                        ++x;
                    }
                    // transparent pixels
                    count = binaryReader.ReadByte();
                    for (int i = 0; i < count; ++i) {
                        colorData[y, x] = new Rgba { A = 0 };
                        ++x;
                    }
                }
                // skip delimiter
                binaryReader.ReadByte();
            }
            // Make sure stream continues right after this format's data
            binaryReader.BaseStream.Seek(start + length, SeekOrigin.Begin);

            bmp.Save(Path.Combine(destinationDirectory, resourceName), ImageFormat);
            Bmp.SaveOffsets(resourceName, xOffset, yOffset);
        }
        // As found in .BOB archives
        public void Load(byte[] imageData, string destinationDirectory, string baseName, BinaryReader binaryReader)
        {
            ushort id = binaryReader.BE_ReadUInt16();
            if (id != 0xF401) {
                throw new Exception(baseName + " is an invalid PlayerBitmap");
            }

            width = 32;
            height = binaryReader.ReadByte();
            var rowDataOffsets = new ushort[height];
            for (int i = 0; i < height; ++i) {
                rowDataOffsets[i] = binaryReader.ReadUInt16();
            }
            xOffset = 16;
            yOffset = binaryReader.ReadByte();

            var bmp = new Bmp(width, height);
            ReadImage(imageData, rowDataOffsets, true, bmp.Data);

            bmp.Save(Path.Combine(destinationDirectory, baseName), ImageFormat);
            Bmp.SaveOffsets(baseName, xOffset, yOffset);
        }
        // Tentative to decrypt the DATA/TEXTURE/GOU*.DAT files, which look like 256x256 paletted textures
        public void Load(string sourceFileName, string destinationDirectory)
        {
            using (var binaryReader = new BinaryReader(File.Open(sourceFileName, FileMode.Open))) {
                if (binaryReader.BaseStream.Length != 65536) {
                    throw new Exception(sourceFileName + " is an invalid texture");
                }

                var palette = PaletteLoader.DefaultPalette;
                var bmp = new Bmp(256, 256);
                var colorData = bmp.Data;

                for (int y = 0; y < 256; ++y) {
                    for (int x = 0; x < 256; ++x) {
                        colorData[y, x] = palette.Colors[binaryReader.ReadByte()];
                    }
                }

                Debug.Assert(binaryReader.BaseStream.Position == binaryReader.BaseStream.Length);
                var destinationFileName = Path.Combine(destinationDirectory, Path.GetFileNameWithoutExtension(sourceFileName));
                bmp.Save(destinationFileName, ImageFormat.Png);
            }
        }
        // Used for loading .BOB archives. Quite a horrible method signature if you ask me!
        public void Load(ushort width, ushort height, short xOffset, short yOffset, byte[] imageData, ushort[] rowDataOffsets, string destinationDirectory, string baseName)
        {
            this.width = width;
            this.height = height;
            this.xOffset = xOffset;
            this.yOffset = yOffset;

            var bmp = new Bmp(width, height);
            ReadImage(imageData, rowDataOffsets, true, bmp.Data);

            bmp.Save(Path.Combine(destinationDirectory, baseName), ImageFormat);
            Bmp.SaveOffsets(baseName, xOffset, yOffset);
        }