public static ArrEntry[] GetArr(int index)
        {
            ArrEntry[] ret = new ArrEntry[64 * 64];

            int[] arrEntry = GetEntry(index);
            if (arrEntry[1] != (ret.Length << 1))
            {
                return(null);
            }

            Rom.Seek(arrEntry[0]);
            for (int sy = 0; sy < 2; sy++)
            {
                for (int sx = 0; sx < 2; sx++)
                {
                    for (int ay = 0; ay < 32; ay++)
                    {
                        for (int ax = 0; ax < 32; ax++)
                        {
                            ret[ax + (sx * 32) + (ay * 64) + (sy * 2048)] = Rom.ReadArrEntry();
                        }
                    }
                }
            }

            return(ret);
        }
        public object Clone()
        {
            ArrEntry ret = new ArrEntry();

            ret.TileNumber = this.TileNumber;
            ret.FlipH      = this.FlipH;
            ret.FlipV      = this.FlipV;
            ret.Palette    = this.Palette;
            return(ret);
        }
        public static ArrEntry[] GetTitleArr()
        {
            var ret = new ArrEntry[32 * 32];

            Rom.Seek(GetPointer(8));
            for (int i = 0; i < ret.Length; i++)
            {
                ret[i] = Rom.ReadArrEntry();
            }
            return(ret);
        }
        public static ArrEntry[] GetArr(int index)
        {
            var entry = GetEntry(index);
            var ret   = new ArrEntry[1024];

            for (int i = 0; i < 1024; i++)
            {
                ret[i] = Rom.ReadArrEntry(entry[0] + (i << 1));
            }
            return(ret);
        }
        public static ArrEntry[] GetLogoArr(int logoNum)
        {
            var ret = new ArrEntry[32 * 32];

            Rom.Seek(GetPointer(logoNum + 2));
            for (int i = 0; i < ret.Length; i++)
            {
                ret[i] = Rom.ReadArrEntry();
            }

            return(ret);
        }
        public static ArrEntry[] GetArr(int index)
        {
            int[]  entry = GetEntry(index);
            byte[] bytes;
            int    res = LZ77.Decompress(Rom, entry[0] + 12, out bytes);

            if (res == -1)
            {
                return(null);
            }
            if (bytes.Length != 2048)
            {
                return(null);
            }

            ArrEntry[] ret = new ArrEntry[1024];
            for (int i = 0; i < 1024; i++)
            {
                ret[i] = bytes.ReadArrEntry(i << 1);
            }

            return(ret);
        }
        public static ArrEntry[] GetArr(int index)
        {
            int[] arrEntry = GetEntry(index);

            // Read the arrangement
            var ret = new ArrEntry[30 * 20];

            Rom.Seek(arrEntry[0]);
            for (int y = 0; y < 20; y++)
            {
                for (int x = 0; x < 30; x++)
                {
                    byte ch = Rom.ReadByte();
                    var  a  = new ArrEntry();
                    a.TileNumber      = (ushort)(ch & 0x3F);
                    a.FlipH           = (ch & 0x40) != 0;
                    a.FlipV           = (ch & 0x80) != 0;
                    a.Palette         = 0;
                    ret[x + (y * 30)] = a;
                }
            }

            return(ret);
        }
        // Returns the arrangement, palette, and a flag indicating whether or not colors were dropped
        unsafe public static object[] SetArrangement(Bitmap _bmp,
                                                     byte[] gfxData, int gfxDataOffset, int tileCount,
                                                     bool useTileset, bool useFlipping,
                                                     Color[] _pal, int palIndex,
                                                     Color transparentColor, bool transparency
                                                     )
        {
            // Convert to Format32bppArgb
            Bitmap bmp;

            if (_bmp.PixelFormat == PixelFormat.Format32bppArgb)
            {
                bmp = _bmp;
            }
            else
            {
                bmp = new Bitmap(_bmp.Width, _bmp.Height, PixelFormat.Format32bppArgb);
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.DrawImage(_bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
                }
                _bmp.Dispose();
            }

            int tilewidth  = bmp.Width >> 3;
            int tileheight = bmp.Height >> 3;

            BitmapData bd  = bmp.LockBits(ImageLockMode.ReadOnly);
            byte *     ptr = (byte *)bd.Scan0;

            // First we need to make a palette
            Color[] pal;
            List <ColorCountPair> colorlist = new List <ColorCountPair>();
            int pcount = transparency ? 16 : 15;

            if (_pal == null)
            {
                // No reference palette given, so let's build one from the image
                pal = new Color[16];

                if (transparency)
                {
                    pal[0] = transparentColor;
                }
                else
                {
                    pal[0] = Color.FromArgb(160, 160, 160);
                }

                // Find the most common colors
                for (int y = 0; y < bd.Height; y++)
                {
                    int offset = bd.Stride * y;
                    for (int x = 0; x < bd.Width; x++)
                    {
                        int b = ptr[offset++] & 0xF8;
                        int g = ptr[offset++] & 0xF8;
                        int r = ptr[offset++] & 0xF8;
                        offset++;

                        Color c        = Color.FromArgb(r, g, b);
                        bool  hascolor = colorlist.Any(cp => cp.col.Equals(c));

                        if (!hascolor)
                        {
                            // This is a new color so add it to the list
                            colorlist.Add(new ColorCountPair(c));
                        }
                        else
                        {
                            // The color is already in the list, so grab a reference to it and increment its counter
                            var ccp = colorlist.First(cp => cp.col.Equals(c));
                            ccp.count++;
                        }
                    }
                }

                // If we hit the transparent color, remove it
                if (transparency && colorlist.Any(cp => cp.col.Equals(transparentColor)))
                {
                    colorlist.Remove(colorlist.First(cp => cp.col.Equals(transparentColor)));
                }

                // Sort the list by its .count fields
                colorlist.Sort();

                // Copy the top 15 into the palette
                for (int i = 0; i < Math.Min(15, colorlist.Count); i++)
                {
                    pal[i + 1] = colorlist[i].col;
                }

                // If we're under 15 colors, just make the rest black
                for (int i = Math.Min(15, colorlist.Count) + 1; i < 16; i++)
                {
                    pal[i] = Color.Black;
                }
            }
            else
            {
                pal = _pal;
            }

            // Create an arrangement
            ArrEntry[] arr = new ArrEntry[tileheight * tilewidth];

            // Start a list for our tile cache
            List <TileHashPair> tilecache = new List <TileHashPair>();

            useFlipping |= useTileset;

            // If we're using the current tileset, then populate the cache
            if (useTileset)
            {
                for (ushort i = 0; i < tileCount; i++)
                {
                    var pixels = gfxData.Read4BppTile(i << 5);
                    tilecache.Add(new TileHashPair(pixels, HashPixels(pixels, false, false), i));
                }
            }

            // Scan each tile
            for (int ty = 0; ty < tileheight; ty++)
            {
                for (int tx = 0; tx < tilewidth; tx++)
                {
                    ArrEntry a = new ArrEntry();
                    a.Palette = (byte)palIndex;

                    var pixels = SetTile(bd, tx, ty, pal);

                    // Hash this tile
                    uint[] hashes =
                    {
                        HashPixels(pixels,               false, false),
                        useFlipping ? HashPixels(pixels, true,  false) : 0,
                        useFlipping ? HashPixels(pixels, false, true) : 0,
                        useFlipping ? HashPixels(pixels, true,  true) : 0
                    };

                    // See if we already have some version of it
                    bool hashmatch = tilecache.Any(th => th.HashMatch(hashes, useFlipping));

                    if (!useTileset && !hashmatch)
                    {
                        // We don't have it, so add it
                        var t = new TileHashPair(pixels, hashes[0], (ushort)tilecache.Count);
                        tilecache.Add(t);

                        a.TileNumber = t.tilenum;
                        a.FlipH      = false;
                        a.FlipV      = false;
                    }
                    else if (useTileset && !hashmatch)
                    {
                        throw new TileMismatchException("Tile has no match!", tx, ty);
                    }
                    else
                    {
                        // We do have it, so use it
                        var t        = tilecache.First(th => th.HashMatch(hashes, useFlipping));
                        var hashflip = t.HashFlip(hashes);

                        a.TileNumber = t.tilenum;
                        a.FlipH      = hashflip[0];
                        a.FlipV      = hashflip[1];
                    }

                    arr[tx + (ty * tilewidth)] = a;
                }
            }

            bmp.UnlockBits(bd);

            // See if we've got too many tiles
            if (tilecache.Count > tileCount)
            {
                throw new TileCountException("Too many tiles!", tilecache.Count, tileCount);
            }

            // Write the tiles to the tileset
            if (!useTileset)
            {
                for (int i = 0; i < tilecache.Count; i++)
                {
                    var pixels = tilecache[i].pixels;
                    gfxData.Write4BppTile(i << 5, pixels);
                }
            }

            return(new object[] { arr, pal, Math.Max(colorlist.Count - (transparency ? 16 : 15), 0) });
        }