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; }
[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());
}
}

View File

@ -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
/// </summary>
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>
/// get the first 0x3000 bytes of ppu data
/// </summary>
@ -33,6 +44,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
/// <returns></returns>
byte[] GetPalRam();
/// <summary>
/// returns the object attribute memory
/// </summary>
/// <returns></returns>
byte[] GetOam();
/// <summary>
/// return one byte of PPU bus data
/// </summary>
@ -56,5 +73,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
/// </summary>
/// <returns></returns>
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.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"];
}
}
}