public void RenderSpriteToScreen(int* screen, int stride, int destx, int desty, ScreenInfo si, int spritenum, OAMInfo oam = null, int xlimit = 1024, int ylimit = 1024, byte[,] spriteMap = null)
        {
            var dims = new[] { SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, 0], SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, 1] };
            if(oam == null)
                oam = new OAMInfo(this, si, spritenum);
            var dim = dims[oam.Size];

            int[] tilebuf = _tileCache[4];

            int baseaddr;
            if (oam.Table == 0)
                baseaddr = si.OBJTable0Addr;
            else
                baseaddr = si.OBJTable1Addr;

            //TODO - flips of 'undocumented' rectangular oam settings are wrong. probably easy to do right, but we need a test

            int bcol = oam.Tile & 0xF;
            int brow = (oam.Tile >> 4) & 0xF;
            for(int oy=0;oy<dim.Height;oy++)
                for (int ox = 0; ox < dim.Width; ox++)
                {
                    int x = ox;
                    int y = oy;

                    int dy, dx;

                    if (oam.HFlip)
                        dx = dim.Width - 1 - x;
                    else dx = x;
                    if (oam.VFlip)
                        dy = dim.Height - 1 - y;
                    else dy = y;

                    dx += destx;
                    dy += desty;

                    if(dx>=xlimit || dy>=ylimit || dx<0 || dy<0)
                        continue;

                    int col = (bcol + (x >> 3)) & 0xF;
                    int row = (brow + (y >> 3)) & 0xF;
                    int sx = x & 0x7;
                    int sy = y & 0x7;

                    int addr = baseaddr*2 + (row * 16 + col) * 64;
                    addr += sy * 8 + sx;

                    int dofs = stride*dy+dx;
                    int color = tilebuf[addr];
                    if (spriteMap != null && color == 0)
                    {
                        //skip transparent pixels
                    }
                    else
                    {
                        screen[dofs] = color;
                        Paletteize(screen, dofs, oam.Palette * 16 + 128, 1);
                        Colorize(screen, dofs, 1);
                        if (spriteMap != null) spriteMap[dx, dy] = (byte)spritenum;
                    }
                }
        }
        public void RenderSpriteToScreen(int *screen, int stride, int destx, int desty, ScreenInfo si, int spritenum, OAMInfo oam = null, int xlimit = 1024, int ylimit = 1024, byte[,] spriteMap = null)
        {
            var dims = new[] { SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, 0], SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, 1] };

            if (oam == null)
            {
                oam = new OAMInfo(this, si, spritenum);
            }
            var dim = dims[oam.Size];

            int[] tilebuf = _tileCache[4];

            int baseaddr;

            if (oam.Table == 0)
            {
                baseaddr = si.OBJTable0Addr;
            }
            else
            {
                baseaddr = si.OBJTable1Addr;
            }

            //TODO - flips of 'undocumented' rectangular oam settings are wrong. probably easy to do right, but we need a test

            int bcol = oam.Tile & 0xF;
            int brow = (oam.Tile >> 4) & 0xF;

            for (int oy = 0; oy < dim.Height; oy++)
            {
                for (int ox = 0; ox < dim.Width; ox++)
                {
                    int x = ox;
                    int y = oy;

                    int dy, dx;

                    if (oam.HFlip)
                    {
                        dx = dim.Width - 1 - x;
                    }
                    else
                    {
                        dx = x;
                    }
                    if (oam.VFlip)
                    {
                        dy = dim.Height - 1 - y;
                    }
                    else
                    {
                        dy = y;
                    }

                    dx += destx;
                    dy += desty;

                    if (dx >= xlimit || dy >= ylimit || dx < 0 || dy < 0)
                    {
                        continue;
                    }

                    int col = (bcol + (x >> 3)) & 0xF;
                    int row = (brow + (y >> 3)) & 0xF;
                    int sx  = x & 0x7;
                    int sy  = y & 0x7;

                    int addr = baseaddr * 2 + (row * 16 + col) * 64;
                    addr += sy * 8 + sx;

                    int dofs  = stride * dy + dx;
                    int color = tilebuf[addr];
                    if (spriteMap != null && color == 0)
                    {
                        //skip transparent pixels
                    }
                    else
                    {
                        screen[dofs] = color;
                        Paletteize(screen, dofs, oam.Palette * 16 + 128, 1);
                        Colorize(screen, dofs, 1);
                        if (spriteMap != null)
                        {
                            spriteMap[dx, dy] = (byte)spritenum;
                        }
                    }
                }
            }
        }