From 285b9581f2811a0cc4a4d1e1d589ac354bcd2285 Mon Sep 17 00:00:00 2001 From: zeromus Date: Sat, 8 Sep 2012 20:03:04 +0000 Subject: [PATCH] snes-work on graphics tools. can now render typical BGs for mode 1. SLOWLY!!!!! this is definitely getting turned into c++ code --- .../Consoles/Nintendo/SNES/LibsnesCore.cs | 42 ++ .../Nintendo/SNES/SNESGraphicsDecoder.cs | 457 +++++++++++++----- .../SNESGraphicsDebugger.Designer.cs | 151 +++++- .../SNESTools/SNESGraphicsDebugger.cs | 39 +- 4 files changed, 534 insertions(+), 155 deletions(-) diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs index 33cfc66cf8..0b33c67c0d 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -310,6 +310,48 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES //apparently this is one frame? timeFrameCounter++; LibsnesDll.snes_run(); + + //SNESGraphicsDecoder dec = new SNESGraphicsDecoder(); + //64x64 @ 4k + //var bw = new BinaryWriter(File.OpenWrite("c:\\dump\\tiles.raw")); + //var tiles = dec.FetchTilemap(0x4000, SNESGraphicsDecoder.ScreenSize.ABCD_64x64); + //foreach (var te in tiles) + //{ + // bw.Write(te.tilenum); + // bw.Write((byte)0); + //} + //bw.Flush(); + //bw.BaseStream.Close(); + + //render tilemap + //dec.CacheTiles(); + //int[] bgScreen = new int[tiles.Length * 64]; + //fixed (int* pbgScreen = &bgScreen[0]) + //{ + // dec.DecodeScreen(pbgScreen, tiles, 0x0000, SNESGraphicsDecoder.ScreenSize.ABCD_64x64, 4, false, 0); + // dec.Paletteize(pbgScreen, 0, 0, bgScreen.Length); + // dec.Colorize(pbgScreen, 0, bgScreen.Length); + //} + ////dec.TrueDecodeTilesNBpp(4); + //dec.CacheTiles(); + //var fs = File.OpenWrite("c:\\dump\\tiles.raw"); + //for (int i = 0; i < bgScreen.Length; i++) + //{ + // fs.WriteByte((byte)((bgScreen[i] >> 0) & 0xFF)); + // fs.WriteByte((byte)((bgScreen[i] >> 8) & 0xFF)); + // fs.WriteByte((byte)((bgScreen[i] >> 16) & 0xFF)); + //} + //fs.Close(); + + //using (var bmp = new System.Drawing.Bitmap(16, 16)) + //{ + // for (int i = 0; i < 256; i++) + // { + // ushort u = dec.cgram[i]; + // bmp.SetPixel(i % 16, i / 16, System.Drawing.Color.FromArgb(SNESGraphicsDecoder.colortable[491520 + u])); + // } + // bmp.Save("c:\\dump\\palette.png"); + //} } //video provider diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs index 10e18ce744..74c037bb56 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs @@ -1,4 +1,6 @@ //http://wiki.superfamicom.org/snes/show/Backgrounds +//http://board.zsnes.com/phpBB3/viewtopic.php?f=10&t=13029&start=75 yoshis island offset per tile demos. and other demos of advanced modes +//but we wont worry about offset per tile modes here. using System; using System.Linq; @@ -14,8 +16,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES { public struct Dimensions { - public Dimensions(int w, int h) { Width = (short)w; Height = (short)h; } - public short Width, Height; + public Dimensions(int w, int h) { Width = w; Height = h; } + public int Width, Height; public override string ToString() { return string.Format("{0}x{1}", Width, Height); @@ -28,13 +30,21 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } public static Dimensions SizeInTilesForBGSize(ScreenSize size) + { + var ret = SizeInBlocksForBGSize(size); + ret.Width *= 32; + ret.Height *= 32; + return ret; + } + + public static Dimensions SizeInBlocksForBGSize(ScreenSize size) { switch (size) { - case ScreenSize.AAAA_32x32: return new Dimensions(32, 32); - case ScreenSize.ABAB_64x32: return new Dimensions(64, 32); - case ScreenSize.AABB_32x64: return new Dimensions(32, 64); - case ScreenSize.ABCD_64x64: return new Dimensions(64, 64); + case ScreenSize.AAAA_32x32: return new Dimensions(1, 1); + case ScreenSize.ABAB_64x32: return new Dimensions(2, 1); + case ScreenSize.AABB_32x64: return new Dimensions(1, 2); + case ScreenSize.ABCD_64x64: return new Dimensions(2, 2); default: throw new Exception(); } } @@ -59,7 +69,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES /// /// the address of the tile data /// - public int TiledataAddr { get { return SCADDR << 13; } } + public int TiledataAddr { get { return TDADDR << 13; } } /// /// Screen size (shape, really.) @@ -71,10 +81,31 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES /// public int Bpp; + /// + /// value of the tilesize register; 1 implies 16x16 tiles + /// + public int TILESIZE; + + /// + /// TileSize; 8 or 16 + /// + public int TileSize { get { return TILESIZE == 1 ? 16 : 8; } } + /// /// The size of the layer, in tiles /// public Dimensions ScreenSizeInTiles { get { return SizeInTilesForBGSize(ScreenSize); } } + + /// + /// The size of the layer, in pixels. This has factored in the selection of 8x8 or 16x16 tiles + /// + public Dimensions ScreenSizeInPixels + { + get + { + return new Dimensions(ScreenSizeInTiles.Width * TileSize, ScreenSizeInTiles.Height * TileSize); + } + } } public class BGInfos @@ -125,6 +156,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES si.BG.BG3.Bpp = ModeBpps[si.Mode.MODE, 2]; si.BG.BG4.Bpp = ModeBpps[si.Mode.MODE, 3]; + si.BG.BG1.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TILESIZE); + si.BG.BG2.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TILESIZE); + si.BG.BG3.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TILESIZE); + si.BG.BG4.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TILESIZE); + si.BG.BG1.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_SCSIZE); si.BG.BG2.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCSIZE); si.BG.BG3.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCSIZE); @@ -133,13 +169,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES si.BG.BG2.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCADDR); si.BG.BG3.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCADDR); si.BG.BG4.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_SCADDR); + si.BG.BG1.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TDADDR); + si.BG.BG2.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TDADDR); + si.BG.BG3.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TDADDR); + si.BG.BG4.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TDADDR); + return si; } - - - static int[] colortable = new int[16 * 32768]; - + //the same basic color table that libsnes uses to convert from snes 555 to rgba32 + public static int[] colortable = new int[16 * 32768]; static SNESGraphicsDecoder() { for (int l = 0; l < 16; l++) @@ -167,7 +206,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } byte* vram; - ushort* cgram, vram16; + public ushort* cgram, vram16; public SNESGraphicsDecoder() { IntPtr block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.VRAM); @@ -177,7 +216,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES cgram = (ushort*)block.ToPointer(); } - public struct TileEnty + public struct TileEntry { public ushort tilenum; public byte palette; @@ -190,21 +229,92 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } /// - /// fetches a normal BG 32x32 tilemap block into the supplied buffer and offset + /// decodes a BG. youll still need to paletteize and colorize it. + /// someone else has to take care of calculating the starting color from the mode and layer number. /// - public void FetchTilemapBlock(TileEnty[] buf, int offset, int addr) + public void DecodeBG(int* screen, int stride, TileEntry[] map, int tiledataBaseAddr, ScreenSize size, int bpp, int tilesize, int paletteStart) { - for (int y = 0, i = offset; y < 32; y++) - for (int x = 0; x < 32; x++, i++) + int ncolors = 1 << bpp; + + int[] tileBuf = new int[16*16]; + var dims = SizeInTilesForBGSize(size); + int count8x8 = tilesize / 8; + int tileSizeBytes = 8 * bpp; + int baseTileNum = tiledataBaseAddr / tileSizeBytes; + int[] tileCache = _tileCache[bpp]; + + int screenWidth = dims.Width * count8x8 * 8; + + for (int mty = 0; mty < dims.Height; mty++) + { + for (int mtx = 0; mtx < dims.Height; mtx++) { - ushort entry = *(ushort*)(vram + addr); - buf[i].tilenum = (ushort)(entry & 0x3FF); - buf[i].palette = (byte)((entry >> 10) & 7); - buf[i].flags = (TileEntryFlags)((entry >> 13) & 7); - addr += 2; + for (int tx = 0; tx < count8x8; tx++) + { + for (int ty = 0; ty < count8x8; ty++) + { + int mapIndex = (mty * count8x8 + ty) * dims.Width + mtx * count8x8 + tx; + var te = map[mapIndex]; + int tileNum = te.tilenum + tx + ty * 16 + baseTileNum; + int srcOfs = tileNum * 64; + for (int i = 0, y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x++, i++) + { + int px = x; + int py = y; + if (te.flags.HasFlag(TileEntryFlags.Horz)) px = 7 - x; + if (te.flags.HasFlag(TileEntryFlags.Vert)) py = 7 - y; + int dstX = (mtx * count8x8 + tx) * 8 + px; + int dstY = (mty * count8x8 + ty) * 8 + py; + int dstOfs = dstY * stride + dstX; + int color = tileCache[srcOfs++]; + color += te.palette * ncolors; + color += paletteStart; + screen[dstOfs] = color; + } + } + } + } } + } } + /// + /// fetches a tilemap. this is simple; apparently only the screen size (shape) is a factor + /// + public TileEntry[] FetchTilemap(int addr, ScreenSize size) + { + var blockDims = SizeInBlocksForBGSize(size); + int blocksw = blockDims.Width; + int blocksh = blockDims.Height; + int width = blockDims.Width * 32; + int height = blockDims.Width * 32; + TileEntry[] buf = new TileEntry[width*height]; + + for (int by = 0; by < blocksh; by++) + { + for (int bx = 0; bx < blocksw; bx++) + { + for (int y = 0; y < 32; y++) + { + for (int x = 0; x < 32; x++) + { + int idx = (by * 32 + y) * width + bx * 32 + x; + ushort entry = *(ushort*)(vram + addr); + buf[idx].tilenum = (ushort)(entry & 0x3FF); + buf[idx].palette = (byte)((entry >> 10) & 7); + buf[idx].flags = (TileEntryFlags)((entry >> 13) & 7); + addr += 2; + } + } + } + } + + return buf; + } + + //TODO - paletteize and colorize could be in one step, for more speed public void Paletteize(int* buf, int offset, int startcolor, int numpixels) { for (int i = 0; i < numpixels; i++) @@ -212,7 +322,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES buf[offset + i] = cgram[startcolor + buf[offset + i]]; } } - public void Colorize(int* buf, int offset, int numpixels) { for (int i = 0; i < numpixels; i++) @@ -221,140 +330,109 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } } - public void Decode8x8x2bpp(int[] buf, int offset, int addr) + int[][] _tileCache = new int[9][]; + + /// + /// Caches all tiles at the 2bpp, 4bpp, and 8bpp decoded states + /// + public void CacheTiles() { - for (int y = 0; y < 8; y++) + //generate 2bpp tiles + int numtiles = 8192; + int[] tiles = new int[8 * 8 * numtiles]; + _tileCache[2] = tiles; + for (int i = 0; i < numtiles; i++) { - byte val = vram[addr + 0]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = val >> (7 - x) & 1; - val = vram[addr + 1]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - addr += 2; + Decode8x8x2bpp(tiles, i * 64, 16 * i, 8); } + + //merge 2bpp tiles into 4bpp and 8bpp + CacheTiles_Merge(2); + CacheTiles_Merge(4); } - public void Decode8x8x4bpp(int[] buf, int offset, int addr) + /// + /// merges one type of tiles with another to create the higher-order bitdepth. + /// TODO - templateize this when we change it to c++ + /// + void CacheTiles_Merge(int fromBpp) { - for (int y = 0; y < 8; y++) - { - byte val = vram[addr + 0]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = val >> (7 - x) & 1; - val = vram[addr + 1]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 16]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 17]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - addr += 2; - } - } + int toBpp = fromBpp * 2; + int shift = fromBpp; + int numtiles = 8192 / toBpp; + int[] tilesDst = new int[8 * 8 * numtiles]; + _tileCache[toBpp] = tilesDst; + int[] tilesSrc = _tileCache[2]; - public void Decode8x8x8bpp(int[] buf, int offset, int addr) - { - for (int y = 0; y < 8; y++) + for (int i = 0; i < numtiles; i++) { - byte val = vram[addr + 0]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = val >> (7 - x) & 1; - val = vram[addr + 1]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 16]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 17]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 32]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 33]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 48]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - val = vram[addr + 49]; - for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); - addr += 2; + int srcAddr = i * 128; + int dstAddr = i * 64; + for (int p = 0; p < 64; p++) + { + int tileA = tilesSrc[srcAddr + p]; + int tileB = tilesSrc[srcAddr + p + 64]; + tilesDst[dstAddr + p] = tileA | (tileB << shift); + } } } /// - /// decodes all the tiles in vram as if they were 2bpp tiles to a 64x64 tile (512x512 pixel) screen + /// decodes an 8x8 tile to a linear framebuffer type thing. fundamental unit of tile decoding. /// - public void DecodeTiles2bpp(int* screen, int stride, int startcolor) + public void Decode8x8x2bpp(int[] buf, int offset, int addr, int stride=8) { - //cant handle this with our speed optimized routines - Debug.Assert(stride == 512); - - int[] tilebuf = new int[8 * 8]; - for (int i = 0; i < 64 * 64; i++) + for (int y = 0; y < 8; y++) { - Decode8x8x2bpp(tilebuf, 0, 16 * i); - int ty = i / 64; - int tx = i % 64; - ty *= 8; - tx *= 8; - for (int y = 0; y < 8; y++) - for (int x = 0; x < 8; x++) - { - screen[(ty + y) * stride + tx + x] = tilebuf[y * 8 + x]; - } + byte val = vram[addr + 1]; + for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = val >> (7 - x) & 1; + val = vram[addr + 0]; + for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = (buf[offset + y * stride + x] << 1) | (val >> (7 - x) & 1); + addr += 2; } + } - Paletteize(screen, 0, startcolor, 64 * 64 * 8 * 8); - Colorize(screen, 0, 64 * 64 * 8 * 8); + public static Dimensions GetDimensionsForTileScreen(int bpp) + { + if (bpp == 2) return new Dimensions(512, 512); + if (bpp == 4) return new Dimensions(512, 256); + if (bpp == 8) return new Dimensions(256, 256); + throw new ApplicationException("weird"); } /// - /// decodes all the tiles in vram as if they were 4bpp tiles to a 64x32 tile (512x256 pixel) screen + /// renders the tiles to a screen with the predefined size + /// we might need 16x16 unscrambling and some other perks here eventually. + /// provide a start color to use as the basis for the palette /// - public void DecodeTiles4bpp(int* screen, int stride, int startcolor) + public void RenderTilesToScreen(int* screen, int stride, int bpp, int startcolor) { - //cant handle this with our speed optimized routines - Debug.Assert(stride == 512); - - int[] tilebuf = new int[8 * 8]; - for (int i = 0; i < 64 * 32; i++) + var dims = GetDimensionsForTileScreen(bpp); + int tilesw = dims.Width / 8; + int numTiles = 8192 / bpp; + int[] tilebuf = _tileCache[bpp]; + for (int i = 0; i < numTiles; i++) { - Decode8x8x4bpp(tilebuf, 0, 32 * i); - int ty = i / 64; - int tx = i % 64; - ty *= 8; - tx *= 8; - for (int y = 0; y < 8; y++) - for (int x = 0; x < 8; x++) + int ty = i / tilesw; + int tx = i % tilesw; + int dstOfs = (ty*8) * stride + tx*8; + int srcOfs = i * 64; + for (int y = 0,p=0; y < 8; y++) + for (int x = 0; x < 8; x++,p++) { - screen[(ty + y) * stride + tx + x] = tilebuf[y * 8 + x]; + screen[dstOfs+y*stride+x] = tilebuf[srcOfs + p]; } } - Paletteize(screen, 0, startcolor, 64 * 32 * 8 * 8); - Colorize(screen, 0, 64 * 32 * 8 * 8); + int numPixels = numTiles * 8 * 8; + Paletteize(screen, 0, startcolor, numPixels); + Colorize(screen, 0, numPixels); } - /// - /// decodes all the tiles in vram as if they were 4bpp tiles to a 32x32 tile (256x256 pixel) screen - /// - public void DecodeTiles8bpp(int* screen, int stride, int startcolor) - { - //cant handle this with our speed optimized routines - Debug.Assert(stride == 256); - - int[] tilebuf = new int[8 * 8]; - for (int i = 0; i < 32 * 32; i++) - { - Decode8x8x8bpp(tilebuf, 0, 64 * i); - int ty = i / 32; - int tx = i % 32; - ty *= 8; - tx *= 8; - for (int y = 0; y < 8; y++) - for (int x = 0; x < 8; x++) - { - screen[(ty + y) * stride + tx + x] = tilebuf[y * 8 + x]; - } - } - - Paletteize(screen, 0, startcolor, 32 * 32 * 8 * 8); - Colorize(screen, 0, 32 * 32 * 8 * 8); - } - } -} + + + } //class SNESGraphicsDecoder +} //namespace //GraphicsDecoder dec = new GraphicsDecoder(); @@ -383,4 +461,125 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES // ms.WriteByte((byte)((i >> 16) & 0xFF)); //} //File.WriteAllBytes("c:\\dump\\file" + ctr, ms.ToArray()); -//ctr++; \ No newline at end of file +//ctr++; + + + //public void Decode8x8x4bpp(int[] buf, int offset, int addr, int stride=8) + //{ + // for (int y = 0; y < 8; y++) + // { + // byte val = vram[addr + 17]; + // for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = val >> (7 - x) & 1; + // val = vram[addr + 16]; + // for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = (buf[offset + y * stride + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 1]; + // for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = (buf[offset + y * stride + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 0]; + // for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = (buf[offset + y * stride + x] << 1) | (val >> (7 - x) & 1); + // addr += 2; + // } + //} + + //public void Decode8x8x8bpp(int[] buf, int offset, int addr, int stride=8) + //{ + // for (int y = 0; y < 8; y++) + // { + // byte val = vram[addr + 49]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (val >> (7 - x) & 1); + // val = vram[addr + 48]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 33]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 32]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 17]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 16]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 1]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = (buf[offset + y * 8 + x] << 1) | (val >> (7 - x) & 1); + // val = vram[addr + 0]; + // for (int x = 0; x < 8; x++) buf[offset + y * 8 + x] = val >> (7 - x) & 1; + // addr += 2; + // } + //} + + + ///// + // /// decodes all the tiles in vram as if they were 2bpp tiles to a 64x64 tile (512x512 pixel) screen + // /// + // public void DecodeTiles2bpp(int* screen, int stride, int startcolor) + // { + // //cant handle this with our speed optimized routines + // Debug.Assert(stride == 512); + + // int[] tilebuf = new int[8 * 8]; + // for (int i = 0; i < 64 * 64; i++) + // { + // Decode8x8x2bpp(tilebuf, 0, 16 * i); + // int ty = i / 64; + // int tx = i % 64; + // ty *= 8; + // tx *= 8; + // for (int y = 0; y < 8; y++) + // for (int x = 0; x < 8; x++) + // { + // screen[(ty + y) * stride + tx + x] = tilebuf[y * 8 + x]; + // } + // } + + // Paletteize(screen, 0, startcolor, 64 * 64 * 8 * 8); + // Colorize(screen, 0, 64 * 64 * 8 * 8); + // } + + // /// + // /// decodes all the tiles in vram as if they were 4bpp tiles to a 64x32 tile (512x256 pixel) screen + // /// + // public void DecodeTiles4bpp(int* screen, int stride, int startcolor) + // { + // ////cant handle this with our speed optimized routines + // //Debug.Assert(stride == 512); + + // //for (int i = 0; i < 64 * 32; i++) + // //{ + // // int ty = i / 64; + // // int tx = i % 64; + // // ty *= 8; + // // tx *= 8; + // // for (int y = 0; y < 8; y++) + // // for (int x = 0; x < 8; x++) + // // { + // // screen[(ty + y) * stride + tx + x] = tilebuf[y * 8 + x]; + // // } + // //} + + // //Paletteize(screen, 0, startcolor, 64 * 32 * 8 * 8); + // //Colorize(screen, 0, 64 * 32 * 8 * 8); + // } + + // /// + // /// decodes all the tiles in vram as if they were 4bpp tiles to a 32x32 tile (256x256 pixel) screen + // /// + // public void DecodeTiles8bpp(int* screen, int stride, int startcolor) + // { + // ////cant handle this with our speed optimized routines + // //Debug.Assert(stride == 256); + + // //int[] tilebuf = new int[8 * 8]; + // //for (int i = 0; i < 32 * 32; i++) + // //{ + // // Decode8x8x8bpp(tilebuf, 0, 64 * i); + // // int ty = i / 32; + // // int tx = i % 32; + // // ty *= 8; + // // tx *= 8; + // // for (int y = 0; y < 8; y++) + // // for (int x = 0; x < 8; x++) + // // { + // // screen[(ty + y) * stride + tx + x] = tilebuf[y * 8 + x]; + // // } + // //} + + // //Paletteize(screen, 0, startcolor, 32 * 32 * 8 * 8); + // //Colorize(screen, 0, 32 * 32 * 8 * 8); + // } \ No newline at end of file diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs index 88e0355532..761f1da03f 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs @@ -30,6 +30,9 @@ { this.label1 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.txtBG1TSizeDescr = new System.Windows.Forms.TextBox(); + this.label15 = new System.Windows.Forms.Label(); + this.txtBG1TSizeBits = new System.Windows.Forms.TextBox(); this.label13 = new System.Windows.Forms.Label(); this.txtBG1Colors = new System.Windows.Forms.TextBox(); this.txtBG1Bpp = new System.Windows.Forms.TextBox(); @@ -57,6 +60,11 @@ this.txtScreenBG3Bpp = new System.Windows.Forms.TextBox(); this.txtScreenBG4Bpp = new System.Windows.Forms.TextBox(); this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.label16 = new System.Windows.Forms.Label(); + this.txtScreenBG4TSize = new System.Windows.Forms.TextBox(); + this.txtScreenBG3TSize = new System.Windows.Forms.TextBox(); + this.txtScreenBG2TSize = new System.Windows.Forms.TextBox(); + this.txtScreenBG1TSize = new System.Windows.Forms.TextBox(); this.comboDisplayType = new System.Windows.Forms.ComboBox(); this.radioButton1 = new System.Windows.Forms.RadioButton(); this.radioButton2 = new System.Windows.Forms.RadioButton(); @@ -88,6 +96,9 @@ // // groupBox1 // + this.groupBox1.Controls.Add(this.txtBG1TSizeDescr); + this.groupBox1.Controls.Add(this.label15); + this.groupBox1.Controls.Add(this.txtBG1TSizeBits); this.groupBox1.Controls.Add(this.label13); this.groupBox1.Controls.Add(this.txtBG1Colors); this.groupBox1.Controls.Add(this.txtBG1Bpp); @@ -106,15 +117,45 @@ this.groupBox1.Controls.Add(this.txtBG1SizeBits); this.groupBox1.Location = new System.Drawing.Point(12, 102); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(327, 189); + this.groupBox1.Size = new System.Drawing.Size(230, 189); this.groupBox1.TabIndex = 3; this.groupBox1.TabStop = false; this.groupBox1.Text = "BG1"; // + // txtBG1TSizeDescr + // + this.txtBG1TSizeDescr.Location = new System.Drawing.Point(83, 43); + this.txtBG1TSizeDescr.Multiline = true; + this.txtBG1TSizeDescr.Name = "txtBG1TSizeDescr"; + this.txtBG1TSizeDescr.ReadOnly = true; + this.txtBG1TSizeDescr.Size = new System.Drawing.Size(72, 18); + this.txtBG1TSizeDescr.TabIndex = 23; + this.txtBG1TSizeDescr.Text = "16x16"; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(33, 46); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(34, 13); + this.label15.TabIndex = 22; + this.label15.Text = "TSize"; + // + // txtBG1TSizeBits + // + this.txtBG1TSizeBits.BackColor = System.Drawing.Color.LightGreen; + this.txtBG1TSizeBits.Location = new System.Drawing.Point(5, 42); + this.txtBG1TSizeBits.Multiline = true; + this.txtBG1TSizeBits.Name = "txtBG1TSizeBits"; + this.txtBG1TSizeBits.ReadOnly = true; + this.txtBG1TSizeBits.Size = new System.Drawing.Size(25, 17); + this.txtBG1TSizeBits.TabIndex = 21; + this.txtBG1TSizeBits.Text = "00"; + // // label13 // this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(236, 24); + this.label13.Location = new System.Drawing.Point(156, 23); this.label13.Name = "label13"; this.label13.Size = new System.Drawing.Size(36, 13); this.label13.TabIndex = 20; @@ -122,28 +163,28 @@ // // txtBG1Colors // - this.txtBG1Colors.Location = new System.Drawing.Point(205, 21); + this.txtBG1Colors.Location = new System.Drawing.Point(83, 21); this.txtBG1Colors.Multiline = true; this.txtBG1Colors.Name = "txtBG1Colors"; this.txtBG1Colors.ReadOnly = true; - this.txtBG1Colors.Size = new System.Drawing.Size(25, 17); + this.txtBG1Colors.Size = new System.Drawing.Size(72, 17); this.txtBG1Colors.TabIndex = 19; this.txtBG1Colors.Text = "00"; // // txtBG1Bpp // - this.txtBG1Bpp.Location = new System.Drawing.Point(150, 21); + this.txtBG1Bpp.Location = new System.Drawing.Point(6, 19); this.txtBG1Bpp.Multiline = true; this.txtBG1Bpp.Name = "txtBG1Bpp"; this.txtBG1Bpp.ReadOnly = true; - this.txtBG1Bpp.Size = new System.Drawing.Size(18, 17); + this.txtBG1Bpp.Size = new System.Drawing.Size(24, 17); this.txtBG1Bpp.TabIndex = 18; this.txtBG1Bpp.Text = "8"; // // label12 // this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(170, 24); + this.label12.Location = new System.Drawing.Point(33, 21); this.label12.Name = "label12"; this.label12.Size = new System.Drawing.Size(32, 13); this.label12.TabIndex = 17; @@ -151,7 +192,7 @@ // // txtBG1TDAddrDescr // - this.txtBG1TDAddrDescr.Location = new System.Drawing.Point(98, 86); + this.txtBG1TDAddrDescr.Location = new System.Drawing.Point(84, 135); this.txtBG1TDAddrDescr.Multiline = true; this.txtBG1TDAddrDescr.Name = "txtBG1TDAddrDescr"; this.txtBG1TDAddrDescr.ReadOnly = true; @@ -162,7 +203,7 @@ // label11 // this.label11.AutoSize = true; - this.label11.Location = new System.Drawing.Point(37, 91); + this.label11.Location = new System.Drawing.Point(34, 140); this.label11.Name = "label11"; this.label11.Size = new System.Drawing.Size(47, 13); this.label11.TabIndex = 14; @@ -170,7 +211,7 @@ // // txtBG1SCAddrDescr // - this.txtBG1SCAddrDescr.Location = new System.Drawing.Point(98, 65); + this.txtBG1SCAddrDescr.Location = new System.Drawing.Point(84, 114); this.txtBG1SCAddrDescr.Multiline = true; this.txtBG1SCAddrDescr.Name = "txtBG1SCAddrDescr"; this.txtBG1SCAddrDescr.ReadOnly = true; @@ -181,7 +222,7 @@ // label9 // this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(277, 45); + this.label9.Location = new System.Drawing.Point(156, 92); this.label9.Name = "label9"; this.label9.Size = new System.Drawing.Size(34, 13); this.label9.TabIndex = 9; @@ -189,7 +230,8 @@ // // txtBG1TDAddrBits // - this.txtBG1TDAddrBits.Location = new System.Drawing.Point(6, 88); + this.txtBG1TDAddrBits.BackColor = System.Drawing.Color.LightGreen; + this.txtBG1TDAddrBits.Location = new System.Drawing.Point(6, 137); this.txtBG1TDAddrBits.Multiline = true; this.txtBG1TDAddrBits.Name = "txtBG1TDAddrBits"; this.txtBG1TDAddrBits.ReadOnly = true; @@ -200,7 +242,7 @@ // label10 // this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(37, 68); + this.label10.Location = new System.Drawing.Point(34, 117); this.label10.Name = "label10"; this.label10.Size = new System.Drawing.Size(46, 13); this.label10.TabIndex = 11; @@ -208,18 +250,18 @@ // // txtBG1SizeInPixels // - this.txtBG1SizeInPixels.Location = new System.Drawing.Point(205, 42); + this.txtBG1SizeInPixels.Location = new System.Drawing.Point(83, 89); this.txtBG1SizeInPixels.Multiline = true; this.txtBG1SizeInPixels.Name = "txtBG1SizeInPixels"; this.txtBG1SizeInPixels.ReadOnly = true; - this.txtBG1SizeInPixels.Size = new System.Drawing.Size(71, 19); + this.txtBG1SizeInPixels.Size = new System.Drawing.Size(72, 19); this.txtBG1SizeInPixels.TabIndex = 8; - this.txtBG1SizeInPixels.Text = "1024z1024"; + this.txtBG1SizeInPixels.Text = "1024x1024"; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(170, 45); + this.label3.Location = new System.Drawing.Point(156, 70); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(32, 13); this.label3.TabIndex = 7; @@ -227,7 +269,8 @@ // // txtBG1SCAddrBits // - this.txtBG1SCAddrBits.Location = new System.Drawing.Point(6, 65); + this.txtBG1SCAddrBits.BackColor = System.Drawing.Color.LightGreen; + this.txtBG1SCAddrBits.Location = new System.Drawing.Point(6, 114); this.txtBG1SCAddrBits.Multiline = true; this.txtBG1SCAddrBits.Name = "txtBG1SCAddrBits"; this.txtBG1SCAddrBits.ReadOnly = true; @@ -237,7 +280,7 @@ // // txtBG1SizeInTiles // - this.txtBG1SizeInTiles.Location = new System.Drawing.Point(98, 42); + this.txtBG1SizeInTiles.Location = new System.Drawing.Point(84, 67); this.txtBG1SizeInTiles.Multiline = true; this.txtBG1SizeInTiles.Name = "txtBG1SizeInTiles"; this.txtBG1SizeInTiles.ReadOnly = true; @@ -248,7 +291,7 @@ // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(37, 45); + this.label2.Location = new System.Drawing.Point(34, 70); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(27, 13); this.label2.TabIndex = 4; @@ -256,7 +299,8 @@ // // txtBG1SizeBits // - this.txtBG1SizeBits.Location = new System.Drawing.Point(6, 42); + this.txtBG1SizeBits.BackColor = System.Drawing.Color.LightGreen; + this.txtBG1SizeBits.Location = new System.Drawing.Point(6, 67); this.txtBG1SizeBits.Multiline = true; this.txtBG1SizeBits.Name = "txtBG1SizeBits"; this.txtBG1SizeBits.ReadOnly = true; @@ -266,6 +310,7 @@ // // txtModeBits // + this.txtModeBits.BackColor = System.Drawing.Color.LightGreen; this.txtModeBits.Location = new System.Drawing.Point(6, 28); this.txtModeBits.Multiline = true; this.txtModeBits.Name = "txtModeBits"; @@ -323,7 +368,7 @@ // label8 // this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(175, 30); + this.label8.Location = new System.Drawing.Point(170, 29); this.label8.Name = "label8"; this.label8.Size = new System.Drawing.Size(25, 13); this.label8.TabIndex = 7; @@ -361,6 +406,11 @@ // // groupBox2 // + this.groupBox2.Controls.Add(this.label16); + this.groupBox2.Controls.Add(this.txtScreenBG4TSize); + this.groupBox2.Controls.Add(this.txtScreenBG3TSize); + this.groupBox2.Controls.Add(this.txtScreenBG2TSize); + this.groupBox2.Controls.Add(this.txtScreenBG1TSize); this.groupBox2.Controls.Add(this.txtScreenBG4Bpp); this.groupBox2.Controls.Add(this.label1); this.groupBox2.Controls.Add(this.txtScreenBG3Bpp); @@ -379,6 +429,55 @@ this.groupBox2.TabStop = false; this.groupBox2.Text = "Screen"; // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(170, 53); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(34, 13); + this.label16.TabIndex = 20; + this.label16.Text = "TSize"; + // + // txtScreenBG4TSize + // + this.txtScreenBG4TSize.Location = new System.Drawing.Point(151, 51); + this.txtScreenBG4TSize.Multiline = true; + this.txtScreenBG4TSize.Name = "txtScreenBG4TSize"; + this.txtScreenBG4TSize.ReadOnly = true; + this.txtScreenBG4TSize.Size = new System.Drawing.Size(18, 17); + this.txtScreenBG4TSize.TabIndex = 19; + this.txtScreenBG4TSize.Text = "16"; + // + // txtScreenBG3TSize + // + this.txtScreenBG3TSize.Location = new System.Drawing.Point(126, 51); + this.txtScreenBG3TSize.Multiline = true; + this.txtScreenBG3TSize.Name = "txtScreenBG3TSize"; + this.txtScreenBG3TSize.ReadOnly = true; + this.txtScreenBG3TSize.Size = new System.Drawing.Size(18, 17); + this.txtScreenBG3TSize.TabIndex = 18; + this.txtScreenBG3TSize.Text = "16"; + // + // txtScreenBG2TSize + // + this.txtScreenBG2TSize.Location = new System.Drawing.Point(102, 51); + this.txtScreenBG2TSize.Multiline = true; + this.txtScreenBG2TSize.Name = "txtScreenBG2TSize"; + this.txtScreenBG2TSize.ReadOnly = true; + this.txtScreenBG2TSize.Size = new System.Drawing.Size(18, 17); + this.txtScreenBG2TSize.TabIndex = 17; + this.txtScreenBG2TSize.Text = "16"; + // + // txtScreenBG1TSize + // + this.txtScreenBG1TSize.Location = new System.Drawing.Point(78, 51); + this.txtScreenBG1TSize.Multiline = true; + this.txtScreenBG1TSize.Name = "txtScreenBG1TSize"; + this.txtScreenBG1TSize.ReadOnly = true; + this.txtScreenBG1TSize.Size = new System.Drawing.Size(18, 17); + this.txtScreenBG1TSize.TabIndex = 16; + this.txtScreenBG1TSize.Text = "16"; + // // comboDisplayType // this.comboDisplayType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; @@ -658,5 +757,13 @@ private System.Windows.Forms.RadioButton radioButton12; private System.Windows.Forms.RadioButton radioButton13; private System.Windows.Forms.Label label14; + private System.Windows.Forms.TextBox txtBG1TSizeDescr; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.TextBox txtBG1TSizeBits; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.TextBox txtScreenBG4TSize; + private System.Windows.Forms.TextBox txtScreenBG3TSize; + private System.Windows.Forms.TextBox txtScreenBG2TSize; + private System.Windows.Forms.TextBox txtScreenBG1TSize; } } \ No newline at end of file diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs index 0738a7a554..0345035dac 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs @@ -50,11 +50,18 @@ namespace BizHawk.MultiClient var si = gd.ScanScreenInfo(); txtModeBits.Text = si.Mode.MODE.ToString(); - txtBG1Bpp.Text = txtScreenBG1Bpp.Text = FormatBpp(si.BG.BG1.Bpp); + txtScreenBG1Bpp.Text = FormatBpp(si.BG.BG1.Bpp); txtScreenBG2Bpp.Text = FormatBpp(si.BG.BG2.Bpp); txtScreenBG3Bpp.Text = FormatBpp(si.BG.BG3.Bpp); txtScreenBG4Bpp.Text = FormatBpp(si.BG.BG4.Bpp); + txtScreenBG1TSize.Text = FormatBpp(si.BG.BG1.TileSize); + txtScreenBG2TSize.Text = FormatBpp(si.BG.BG2.TileSize); + txtScreenBG3TSize.Text = FormatBpp(si.BG.BG3.TileSize); + txtScreenBG4TSize.Text = FormatBpp(si.BG.BG4.TileSize); + txtBG1TSizeBits.Text = si.BG.BG1.TILESIZE.ToString(); + txtBG1TSizeDescr.Text = string.Format("{0}x{0}", si.BG.BG1.TileSize); + txtBG1Bpp.Text = FormatBpp(si.BG.BG1.Bpp); txtBG1SizeBits.Text = si.BG.BG1.SCSIZE.ToString(); txtBG1SizeInTiles.Text = FormatScreenSizeInTiles(si.BG.BG1.ScreenSize); txtBG1SCAddrBits.Text = si.BG.BG1.SCADDR.ToString(); @@ -62,6 +69,11 @@ namespace BizHawk.MultiClient txtBG1Colors.Text = (1 << si.BG.BG1.Bpp).ToString(); txtBG1TDAddrBits.Text = si.BG.BG1.TDADDR.ToString(); txtBG1TDAddrDescr.Text = FormatVramAddress(si.BG.BG1.TDADDR << 13); + + var sizeInPixels = SNESGraphicsDecoder.SizeInTilesForBGSize(si.BG.BG1.ScreenSize); + sizeInPixels.Width *= si.BG.BG1.TileSize; + sizeInPixels.Height *= si.BG.BG1.TileSize; + txtBG1SizeInPixels.Text = string.Format("{0}x{1}", sizeInPixels.Width, sizeInPixels.Height); RenderView(); } @@ -83,21 +95,38 @@ namespace BizHawk.MultiClient }; var gd = new SNESGraphicsDecoder(); + gd.CacheTiles(); string selection = comboDisplayType.SelectedItem as string; if (selection == "Tiles as 2bpp") { allocate(512, 512); - gd.DecodeTiles2bpp(pixelptr, stride / 4, 0); + gd.RenderTilesToScreen(pixelptr, stride / 4, 2, 0); } if (selection == "Tiles as 4bpp") { allocate(512, 512); - gd.DecodeTiles4bpp(pixelptr, stride / 4, 0); + gd.RenderTilesToScreen(pixelptr, stride / 4, 4, 0); } if (selection == "Tiles as 8bpp") { allocate(256, 256); - gd.DecodeTiles8bpp(pixelptr, stride / 4, 0); + gd.RenderTilesToScreen(pixelptr, stride / 4, 8, 0); + } + if (selection == "BG1" || selection == "BG2" || selection == "BG3" /*|| selection == "BG4"*/) + { + int bgnum = int.Parse(selection.Substring(2)); + var si = gd.ScanScreenInfo(); + var bg = si.BG[bgnum]; + var dims = bg.ScreenSizeInPixels; + allocate(dims.Width, dims.Height); + int numPixels = dims.Width * dims.Height; + System.Diagnostics.Debug.Assert(stride / 4 == dims.Width); + + var map = gd.FetchTilemap(bg.ScreenAddr, bg.ScreenSize); + int paletteStart = 0; + gd.DecodeBG(pixelptr, stride / 4, map, bg.TiledataAddr, bg.ScreenSize, bg.Bpp, bg.TileSize, paletteStart); + gd.Paletteize(pixelptr, 0, 0, numPixels); + gd.Colorize(pixelptr, 0, numPixels); } if (bmp != null) @@ -114,5 +143,7 @@ namespace BizHawk.MultiClient } + + } }