NES: ppu view internal infrastructure

This commit is contained in:
goyuken 2014-12-17 02:01:48 +00:00
parent bb85875b94
commit 50704247fa
3 changed files with 147 additions and 93 deletions

View File

@ -30,6 +30,8 @@ namespace BizHawk.Client.EmuHawk
private NES _nes { get; set; } private NES _nes { get; set; }
[RequiredService] [RequiredService]
private INESPPUViewable xxx { get; set; } private INESPPUViewable xxx { get; set; }
[RequiredService]
private IEmulator _emu { get; set; }
public NesPPU() public NesPPU()
{ {
@ -89,10 +91,10 @@ namespace BizHawk.Client.EmuHawk
{ {
return (byte)((_ppuBus[address] >> (7 - bit)) & 1); return (byte)((_ppuBus[address] >> (7 - bit)) & 1);
} }
private bool CheckChange() private bool CheckChange()
{ {
var changed = false; bool changed = false;
for (var i = 0; i < 0x20; i++) for (var i = 0; i < 0x20; i++)
{ {
_palRamPrev[i] = _palRam[i]; _palRamPrev[i] = _palRam[i];
@ -121,7 +123,7 @@ namespace BizHawk.Client.EmuHawk
return changed; 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 b0;
int b1; int b1;
@ -133,7 +135,7 @@ namespace BizHawk.Client.EmuHawk
ImageLockMode.WriteOnly, ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb); PixelFormat.Format32bppArgb);
var framebuf = (int*)bmpdata.Scan0.ToPointer(); int* framebuf = (int*)bmpdata.Scan0;
for (int z = 0; z < 2; z++) for (int z = 0; z < 2; z++)
{ {
int pal; int pal;
@ -152,7 +154,7 @@ namespace BizHawk.Client.EmuHawk
b1 = (byte)((src[address + 8] >> (7 - x)) & 1); b1 = (byte)((src[address + 8] >> (7 - x)) & 1);
value = (byte)(b0 + (b1 << 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); int adr = (x + (j << 3)) + (y + (i << 3)) * (bmpdata.Stride >> 2);
framebuf[adr + (z << 7)] = cvalue; framebuf[adr + (z << 7)] = cvalue;
} }
@ -172,105 +174,109 @@ namespace BizHawk.Client.EmuHawk
return; 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; _forceChange = false;
int b1;
byte value;
int cvalue;
if (CheckChange()) // Pattern Viewer
for (var i = 0; i < 16; i++)
{ {
_forceChange = false; PaletteView.BgPalettesPrev[i].Value = PaletteView.BgPalettes[i].Value;
PaletteView.SpritePalettesPrev[i].Value = PaletteView.SpritePalettes[i].Value;
// Pattern Viewer PaletteView.BgPalettes[i].Value = FinalPalette[PALRAM[PaletteView.BgPalettes[i].Address]];
for (var i = 0; i < 16; i++) PaletteView.SpritePalettes[i].Value = FinalPalette[PALRAM[PaletteView.SpritePalettes[i].Address]];
{
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);
} }
var bmpdata2 = SpriteView.sprites.LockBits(new Rectangle(new Point(0, 0), SpriteView.sprites.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); if (PaletteView.HasChanged())
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++)
{ {
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); patternAddr = (TileNum >> 1) * 0x20;
int TileNum = _nes.ppu.OAM[BaseAddr + 1]; patternAddr += 0x1000 * (TileNum & 1);
int patternAddr; }
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) if (is8x16)
{ {
patternAddr = (TileNum >> 1) * 0x20; patternAddr += 0x10;
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++)
{
for (int y = 0; y < 8; y++) for (int y = 0; y < 8; y++)
{ {
int address = patternAddr + y; int address = patternAddr + y;
b0 = (byte)((_ppuBus[address] >> (7 - x)) & 1); b0 = (byte)((_ppuBus[address] >> (7 - x)) & 1);
b1 = (byte)((_ppuBus[address + 8] >> (7 - x)) & 1); b1 = (byte)((_ppuBus[address + 8] >> (7 - x)) & 1);
value = (byte)(b0 + (b1 << 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; framebuf2[adr] = cvalue;
} }
if (is8x16) patternAddr -= 0x10;
{
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;
}
} }
} }
} }
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() private void ClearDetails()
@ -609,12 +615,14 @@ namespace BizHawk.Client.EmuHawk
if (e.X >= SpriteView.ClientRectangle.Right) return; if (e.X >= SpriteView.ClientRectangle.Right) return;
if (e.Y >= SpriteView.ClientRectangle.Bottom) 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); var spriteNumber = ((e.Y / 24) * 16) + (e.X / 16);
int x = _nes.ppu.OAM[(spriteNumber * 4) + 3]; int x = OAM[(spriteNumber * 4) + 3];
int y = _nes.ppu.OAM[spriteNumber * 4]; int y = OAM[spriteNumber * 4];
var color = _nes.ppu.OAM[(spriteNumber * 4) + 2] & 0x03; var color = OAM[(spriteNumber * 4) + 2] & 0x03;
var attributes = _nes.ppu.OAM[(spriteNumber * 4) + 2]; var attributes = OAM[(spriteNumber * 4) + 2];
var flags = "Flags: "; var flags = "Flags: ";
int h = GetBit(attributes, 6); int h = GetBit(attributes, 6);
@ -639,7 +647,7 @@ namespace BizHawk.Client.EmuHawk
flags += "Front"; flags += "Front";
} }
int tile = _nes.ppu.OAM[spriteNumber * 4 + 1]; int tile = OAM[spriteNumber * 4 + 1];
if (is8x16) if (is8x16)
{ {
if ((tile & 1) != 0) if ((tile & 1) != 0)
@ -702,15 +710,17 @@ namespace BizHawk.Client.EmuHawk
var bmp = new Bitmap(64, 64); var bmp = new Bitmap(64, 64);
var g = Graphics.FromImage(bmp); var g = Graphics.FromImage(bmp);
byte[] PALRAM = xxx.GetPalRam();
if (baseAddr == 0x3F00) if (baseAddr == 0x3F00)
{ {
val = _nes.ppu.PALRAM[PaletteView.BgPalettes[column].Address]; val = PALRAM[PaletteView.BgPalettes[column].Address];
ValueLabel.Text = "ID: BG" + (column / 4); ValueLabel.Text = "ID: BG" + (column / 4);
g.FillRectangle(new SolidBrush(PaletteView.BgPalettes[column].Color), 0, 0, 64, 64); g.FillRectangle(new SolidBrush(PaletteView.BgPalettes[column].Color), 0, 0, 64, 64);
} }
else else
{ {
val = _nes.ppu.PALRAM[PaletteView.SpritePalettes[column].Address]; val = PALRAM[PaletteView.SpritePalettes[column].Address];
ValueLabel.Text = "ID: SPR" + (column / 4); ValueLabel.Text = "ID: SPR" + (column / 4);
g.FillRectangle(new SolidBrush(PaletteView.SpritePalettes[column].Color), 0, 0, 64, 64); 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; tile += (e.Y / 8) * 16;
var usage = "Usage: "; var usage = "Usage: ";
if ((_nes.ppu.reg_2000.Value & 0x10) << 4 == ((address >> 4) & 0x100)) if (xxx.BGBaseHigh == address >= 0x1000) // bghigh
{ {
usage = "BG"; usage = "BG";
} }
else if (((_nes.ppu.reg_2000.Value & 0x08) << 5) == ((address >> 4) & 0x100)) else if (xxx.SPBaseHigh == address >= 0x1000) // sphigh
{ {
usage = "SPR"; usage = "SPR";
} }
if ((_nes.ppu.reg_2000.Value & 0x20) > 0) if (xxx.SPTall) // spbig
{ {
usage += " (SPR16)"; usage += " (SPR16)";
} }
@ -841,7 +851,7 @@ namespace BizHawk.Client.EmuHawk
private void CHRROMViewReload() private void CHRROMViewReload()
{ {
CHRROM = _nes.MemoryDomains["CHR VROM"]; CHRROM = xxx.GetCHRROM();
if (CHRROM == null) if (CHRROM == null)
{ {
numericUpDownCHRROMBank.Enabled = false; numericUpDownCHRROMBank.Enabled = false;
@ -865,7 +875,7 @@ namespace BizHawk.Client.EmuHawk
for (int i = 0; i < 8192; i++) for (int i = 0; i < 8192; i++)
chrromcache[i] = CHRROM.PeekByte(offs + i); chrromcache[i] = CHRROM.PeekByte(offs + i);
DrawPatternView(CHRROMView, chrromcache); DrawPatternView(CHRROMView, chrromcache, xxx.GetPalette(), xxx.GetPalRam());
} }
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.NES namespace BizHawk.Emulation.Cores.Nintendo.NES
{ {
@ -21,6 +22,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
/// </summary> /// </summary>
bool BGBaseHigh { get; } bool BGBaseHigh { get; }
/// <summary>
/// true if sp tile indexes start at 0x1000 instead of 0x0000 (8x8 mode only)
/// </summary>
bool SPBaseHigh { get; }
/// <summary>
/// true if sprites are 8x16
/// </summary>
bool SPTall { get; }
/// <summary> /// <summary>
/// get the first 0x3000 bytes of ppu data /// get the first 0x3000 bytes of ppu data
/// </summary> /// </summary>
@ -33,6 +44,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
/// <returns></returns> /// <returns></returns>
byte[] GetPalRam(); byte[] GetPalRam();
/// <summary>
/// returns the object attribute memory
/// </summary>
/// <returns></returns>
byte[] GetOam();
/// <summary> /// <summary>
/// return one byte of PPU bus data /// return one byte of PPU bus data
/// </summary> /// </summary>
@ -56,5 +73,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
byte[] GetExRam(); byte[] GetExRam();
/// <summary>
/// get memory domain for chr rom; return null if RAM or other N/A. for direct viewing of ROM tiles.
/// </summary>
/// <returns></returns>
MemoryDomain GetCHRROM();
} }
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.NES namespace BizHawk.Emulation.Cores.Nintendo.NES
{ {
@ -17,6 +18,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
get { return ppu.reg_2000.bg_pattern_hi; } 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() public byte[] GetPPUBus()
{ {
byte[] ret = new byte[0x3000]; byte[] ret = new byte[0x3000];
@ -32,6 +43,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
return ppu.PALRAM; return ppu.PALRAM;
} }
public byte[] GetOam()
{
return ppu.OAM;
}
public byte PeekPPU(int addr) public byte PeekPPU(int addr)
{ {
return board.PeekPPU(addr); return board.PeekPPU(addr);
@ -65,5 +81,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
} }
public MemoryDomain GetCHRROM()
{
return MemoryDomains["CHR VROM"];
}
} }
} }