diff --git a/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs b/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs index 85f2863b81..cdc82c0893 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs @@ -30,6 +30,8 @@ namespace BizHawk.Client.EmuHawk private NES _nes { get; set; } [RequiredService] private INESPPUViewable xxx { get; set; } + [RequiredService] + private IEmulator _emu { get; set; } public NesPPU() { @@ -89,10 +91,10 @@ namespace BizHawk.Client.EmuHawk { return (byte)((_ppuBus[address] >> (7 - bit)) & 1); } - + private bool CheckChange() { - var changed = false; + bool changed = false; for (var i = 0; i < 0x20; i++) { _palRamPrev[i] = _palRam[i]; @@ -121,7 +123,7 @@ namespace BizHawk.Client.EmuHawk return changed; } - private unsafe void DrawPatternView(PatternViewer dest, byte[] src) + private unsafe void DrawPatternView(PatternViewer dest, byte[] src, int[] FinalPalette, byte[] PALRAM) { int b0; int b1; @@ -133,7 +135,7 @@ namespace BizHawk.Client.EmuHawk ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - var framebuf = (int*)bmpdata.Scan0.ToPointer(); + int* framebuf = (int*)bmpdata.Scan0; for (int z = 0; z < 2; z++) { int pal; @@ -152,7 +154,7 @@ namespace BizHawk.Client.EmuHawk b1 = (byte)((src[address + 8] >> (7 - x)) & 1); value = (byte)(b0 + (b1 << 1)); - cvalue = _nes.LookupColor(_nes.ppu.PALRAM[value + (pal << 2)]); + cvalue = FinalPalette[PALRAM[value + (pal << 2)]]; int adr = (x + (j << 3)) + (y + (i << 3)) * (bmpdata.Stride >> 2); framebuf[adr + (z << 7)] = cvalue; } @@ -172,105 +174,109 @@ namespace BizHawk.Client.EmuHawk return; } - if (_nes.Frame % RefreshRate.Value == 0 || now) + if (_emu.Frame % RefreshRate.Value != 0 && !now) + return; + + byte[] PALRAM = xxx.GetPalRam(); + int[] FinalPalette = xxx.GetPalette(); + byte[] OAM = xxx.GetOam(); + + int b0; + int b1; + byte value; + int cvalue; + + if (CheckChange()) { - int b0; - int b1; - byte value; - int cvalue; + _forceChange = false; - if (CheckChange()) + // Pattern Viewer + for (var i = 0; i < 16; i++) { - _forceChange = false; - - // Pattern Viewer - for (var i = 0; i < 16; i++) - { - PaletteView.BgPalettesPrev[i].Value = PaletteView.BgPalettes[i].Value; - PaletteView.SpritePalettesPrev[i].Value = PaletteView.SpritePalettes[i].Value; - PaletteView.BgPalettes[i].Value = _nes.LookupColor(_nes.ppu.PALRAM[PaletteView.BgPalettes[i].Address]); - PaletteView.SpritePalettes[i].Value = _nes.LookupColor(_nes.ppu.PALRAM[PaletteView.SpritePalettes[i].Address]); - } - - if (PaletteView.HasChanged()) - { - PaletteView.Refresh(); - } - - DrawPatternView(PatternView, _ppuBus); + PaletteView.BgPalettesPrev[i].Value = PaletteView.BgPalettes[i].Value; + PaletteView.SpritePalettesPrev[i].Value = PaletteView.SpritePalettes[i].Value; + PaletteView.BgPalettes[i].Value = FinalPalette[PALRAM[PaletteView.BgPalettes[i].Address]]; + PaletteView.SpritePalettes[i].Value = FinalPalette[PALRAM[PaletteView.SpritePalettes[i].Address]]; } - var bmpdata2 = SpriteView.sprites.LockBits(new Rectangle(new Point(0, 0), SpriteView.sprites.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - var framebuf2 = (int*)bmpdata2.Scan0.ToPointer(); - - int pt_add = _nes.ppu.reg_2000.obj_pattern_hi ? 0x1000 : 0; - bool is8x16 = _nes.ppu.reg_2000.obj_size_16; - - - // Sprite Viewer - for (int n = 0; n < 4; n++) + if (PaletteView.HasChanged()) { - for (int r = 0; r < 16; r++) + PaletteView.Refresh(); + } + + DrawPatternView(PatternView, _ppuBus, FinalPalette, PALRAM); + } + + var bmpdata2 = SpriteView.sprites.LockBits(new Rectangle(new Point(0, 0), SpriteView.sprites.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + var framebuf2 = (int*)bmpdata2.Scan0.ToPointer(); + + int pt_add = xxx.SPBaseHigh ? 0x1000 : 0; + bool is8x16 = xxx.SPTall; + + + // Sprite Viewer + for (int n = 0; n < 4; n++) + { + for (int r = 0; r < 16; r++) + { + int BaseAddr = (r << 2) + (n << 6); + int TileNum = OAM[BaseAddr + 1]; + int patternAddr; + + if (is8x16) { - int BaseAddr = (r << 2) + (n << 6); - int TileNum = _nes.ppu.OAM[BaseAddr + 1]; - int patternAddr; + patternAddr = (TileNum >> 1) * 0x20; + patternAddr += 0x1000 * (TileNum & 1); + } + else + { + patternAddr = TileNum * 0x10; + patternAddr += pt_add; + } + + int Attributes = OAM[BaseAddr + 2]; + int Palette = Attributes & 0x03; + + for (int x = 0; x < 8; x++) + { + for (int y = 0; y < 8; y++) + { + int address = patternAddr + y; + b0 = (byte)((_ppuBus[address] >> (7 - x)) & 1); + b1 = (byte)((_ppuBus[address + 8] >> (7 - x)) & 1); + value = (byte)(b0 + (b1 << 1)); + cvalue = FinalPalette[PALRAM[16 + value + (Palette << 2)]]; + + int adr = (x + (r * 16)) + (y + (n * 24)) * (bmpdata2.Stride >> 2); + framebuf2[adr] = cvalue; + } if (is8x16) { - patternAddr = (TileNum >> 1) * 0x20; - patternAddr += 0x1000 * (TileNum & 1); - } - else - { - patternAddr = TileNum * 0x10; - patternAddr += pt_add; - } - - int Attributes = _nes.ppu.OAM[BaseAddr + 2]; - int Palette = Attributes & 0x03; - - for (int x = 0; x < 8; x++) - { + patternAddr += 0x10; for (int y = 0; y < 8; y++) { int address = patternAddr + y; b0 = (byte)((_ppuBus[address] >> (7 - x)) & 1); b1 = (byte)((_ppuBus[address + 8] >> (7 - x)) & 1); value = (byte)(b0 + (b1 << 1)); - cvalue = _nes.LookupColor(_nes.ppu.PALRAM[16 + value + (Palette << 2)]); + cvalue = FinalPalette[PALRAM[16 + value + (Palette << 2)]]; - int adr = (x + (r * 16)) + (y + (n * 24)) * (bmpdata2.Stride >> 2); + int adr = (x + (r << 4)) + ((y + 8) + (n * 24)) * (bmpdata2.Stride >> 2); framebuf2[adr] = cvalue; } - if (is8x16) - { - patternAddr += 0x10; - for (int y = 0; y < 8; y++) - { - int address = patternAddr + y; - b0 = (byte)((_ppuBus[address] >> (7 - x)) & 1); - b1 = (byte)((_ppuBus[address + 8] >> (7 - x)) & 1); - value = (byte)(b0 + (b1 << 1)); - cvalue = _nes.LookupColor(_nes.ppu.PALRAM[16 + value + (Palette << 2)]); - - int adr = (x + (r << 4)) + ((y+8) + (n * 24)) * (bmpdata2.Stride >> 2); - framebuf2[adr] = cvalue; - } - - patternAddr -= 0x10; - } + patternAddr -= 0x10; } } } - - SpriteView.sprites.UnlockBits(bmpdata2); - SpriteView.Refresh(); - - HandleSpriteViewMouseMove(SpriteView.PointToClient(MousePosition)); - HandlePaletteViewMouseMove(PaletteView.PointToClient(MousePosition)); } + + SpriteView.sprites.UnlockBits(bmpdata2); + SpriteView.Refresh(); + + HandleSpriteViewMouseMove(SpriteView.PointToClient(MousePosition)); + HandlePaletteViewMouseMove(PaletteView.PointToClient(MousePosition)); } private void ClearDetails() @@ -609,12 +615,14 @@ namespace BizHawk.Client.EmuHawk if (e.X >= SpriteView.ClientRectangle.Right) return; if (e.Y >= SpriteView.ClientRectangle.Bottom) return; - bool is8x16 = _nes.ppu.reg_2000.obj_size_16; + byte[] OAM = xxx.GetOam(); + + bool is8x16 = xxx.SPTall; var spriteNumber = ((e.Y / 24) * 16) + (e.X / 16); - int x = _nes.ppu.OAM[(spriteNumber * 4) + 3]; - int y = _nes.ppu.OAM[spriteNumber * 4]; - var color = _nes.ppu.OAM[(spriteNumber * 4) + 2] & 0x03; - var attributes = _nes.ppu.OAM[(spriteNumber * 4) + 2]; + int x = OAM[(spriteNumber * 4) + 3]; + int y = OAM[spriteNumber * 4]; + var color = OAM[(spriteNumber * 4) + 2] & 0x03; + var attributes = OAM[(spriteNumber * 4) + 2]; var flags = "Flags: "; int h = GetBit(attributes, 6); @@ -639,7 +647,7 @@ namespace BizHawk.Client.EmuHawk flags += "Front"; } - int tile = _nes.ppu.OAM[spriteNumber * 4 + 1]; + int tile = OAM[spriteNumber * 4 + 1]; if (is8x16) { if ((tile & 1) != 0) @@ -702,15 +710,17 @@ namespace BizHawk.Client.EmuHawk var bmp = new Bitmap(64, 64); var g = Graphics.FromImage(bmp); + byte[] PALRAM = xxx.GetPalRam(); + if (baseAddr == 0x3F00) { - val = _nes.ppu.PALRAM[PaletteView.BgPalettes[column].Address]; + val = PALRAM[PaletteView.BgPalettes[column].Address]; ValueLabel.Text = "ID: BG" + (column / 4); g.FillRectangle(new SolidBrush(PaletteView.BgPalettes[column].Color), 0, 0, 64, 64); } else { - val = _nes.ppu.PALRAM[PaletteView.SpritePalettes[column].Address]; + val = PALRAM[PaletteView.SpritePalettes[column].Address]; ValueLabel.Text = "ID: SPR" + (column / 4); g.FillRectangle(new SolidBrush(PaletteView.SpritePalettes[column].Color), 0, 0, 64, 64); } @@ -784,16 +794,16 @@ namespace BizHawk.Client.EmuHawk tile += (e.Y / 8) * 16; var usage = "Usage: "; - if ((_nes.ppu.reg_2000.Value & 0x10) << 4 == ((address >> 4) & 0x100)) + if (xxx.BGBaseHigh == address >= 0x1000) // bghigh { usage = "BG"; } - else if (((_nes.ppu.reg_2000.Value & 0x08) << 5) == ((address >> 4) & 0x100)) + else if (xxx.SPBaseHigh == address >= 0x1000) // sphigh { usage = "SPR"; } - if ((_nes.ppu.reg_2000.Value & 0x20) > 0) + if (xxx.SPTall) // spbig { usage += " (SPR16)"; } @@ -841,7 +851,7 @@ namespace BizHawk.Client.EmuHawk private void CHRROMViewReload() { - CHRROM = _nes.MemoryDomains["CHR VROM"]; + CHRROM = xxx.GetCHRROM(); if (CHRROM == null) { numericUpDownCHRROMBank.Enabled = false; @@ -865,7 +875,7 @@ namespace BizHawk.Client.EmuHawk for (int i = 0; i < 8192; i++) chrromcache[i] = CHRROM.PeekByte(offs + i); - DrawPatternView(CHRROMView, chrromcache); + DrawPatternView(CHRROMView, chrromcache, xxx.GetPalette(), xxx.GetPalRam()); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/INESPPUViewable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/INESPPUViewable.cs index ce0feadb49..3b815c0217 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/INESPPUViewable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/INESPPUViewable.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Nintendo.NES { @@ -21,6 +22,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES /// bool BGBaseHigh { get; } + /// + /// true if sp tile indexes start at 0x1000 instead of 0x0000 (8x8 mode only) + /// + bool SPBaseHigh { get; } + + /// + /// true if sprites are 8x16 + /// + bool SPTall { get; } + /// /// get the first 0x3000 bytes of ppu data /// @@ -33,6 +44,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES /// byte[] GetPalRam(); + /// + /// returns the object attribute memory + /// + /// + byte[] GetOam(); + /// /// return one byte of PPU bus data /// @@ -56,5 +73,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES /// /// byte[] GetExRam(); + + /// + /// get memory domain for chr rom; return null if RAM or other N/A. for direct viewing of ROM tiles. + /// + /// + MemoryDomain GetCHRROM(); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.INESPPUViewable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.INESPPUViewable.cs index 691993979e..5bb897f034 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.INESPPUViewable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.INESPPUViewable.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Nintendo.NES { @@ -17,6 +18,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES get { return ppu.reg_2000.bg_pattern_hi; } } + public bool SPBaseHigh + { + get { return ppu.reg_2000.obj_pattern_hi; } + } + + public bool SPTall + { + get { return ppu.reg_2000.obj_size_16; } + } + public byte[] GetPPUBus() { byte[] ret = new byte[0x3000]; @@ -32,6 +43,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES return ppu.PALRAM; } + public byte[] GetOam() + { + return ppu.OAM; + } + public byte PeekPPU(int addr) { return board.PeekPPU(addr); @@ -65,5 +81,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES throw new InvalidOperationException(); } } + + public MemoryDomain GetCHRROM() + { + return MemoryDomains["CHR VROM"]; + } } }