Implement snes graphics debugger for the new bsnes core (#3367)
* Partial port of graphics debugger to new BSNES
* minimal "working" copy-paste
* small fix for the previous commit
* Implement more stuff
* no idea whose responsibility "EnterExit" is but this should work
* add support for backdropcolor
i have 0% trust in this code
* implement mode7, apply backcolor on load
* 🙈
un-"implement" the nonfunctional scanlinehookmanager as well as the non-functional palette setting logic
- this may actually break config lol
* don't break libsnes config
* Provide IBSNESForGfxDebugger in the subbsnes core
* Remove redundant semicolon
* Clean up diff of `comboPalette_SelectedIndexChanged`
* Fix crash
Co-authored-by: YoshiRulz <OSSYoshiRulz@gmail.com>
This commit is contained in:
parent
28d62e69d7
commit
6f0953aaa3
Binary file not shown.
|
@ -1708,7 +1708,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private void SnesSubMenu_DropDownOpened(object sender, EventArgs e)
|
private void SnesSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SNESControllerConfigurationMenuItem.Enabled = MovieSession.Movie.NotActive();
|
SNESControllerConfigurationMenuItem.Enabled = MovieSession.Movie.NotActive();
|
||||||
SnesGfxDebuggerMenuItem.Enabled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DialogResult OpenOldBSNESGamepadSettingsDialog(ISettingsAdapter settable)
|
private DialogResult OpenOldBSNESGamepadSettingsDialog(ISettingsAdapter settable)
|
||||||
|
|
|
@ -2042,21 +2042,17 @@ namespace BizHawk.Client.EmuHawk
|
||||||
case VSystemID.Raw.SNES when Emulator is LibsnesCore { IsSGB: true }: // doesn't use "SGB" sysID
|
case VSystemID.Raw.SNES when Emulator is LibsnesCore { IsSGB: true }: // doesn't use "SGB" sysID
|
||||||
SNESSubMenu.Text = "&SGB";
|
SNESSubMenu.Text = "&SGB";
|
||||||
SNESSubMenu.Visible = true;
|
SNESSubMenu.Visible = true;
|
||||||
SnesGfxDebuggerMenuItem.Visible = true;
|
|
||||||
break;
|
break;
|
||||||
case VSystemID.Raw.SNES when Emulator is LibsnesCore { IsSGB: false }:
|
case VSystemID.Raw.SNES when Emulator is LibsnesCore { IsSGB: false }:
|
||||||
SNESSubMenu.Text = "&SNES";
|
SNESSubMenu.Text = "&SNES";
|
||||||
SNESSubMenu.Visible = true;
|
SNESSubMenu.Visible = true;
|
||||||
SnesGfxDebuggerMenuItem.Visible = true;
|
|
||||||
break;
|
break;
|
||||||
case VSystemID.Raw.SNES when Emulator is BsnesCore bsnesCore:
|
case VSystemID.Raw.SNES when Emulator is BsnesCore bsnesCore:
|
||||||
SNESSubMenu.Text = bsnesCore.IsSGB ? "&SGB" : "&SNES";
|
SNESSubMenu.Text = bsnesCore.IsSGB ? "&SGB" : "&SNES";
|
||||||
SnesGfxDebuggerMenuItem.Visible = false;
|
|
||||||
SNESSubMenu.Visible = true;
|
SNESSubMenu.Visible = true;
|
||||||
break;
|
break;
|
||||||
case VSystemID.Raw.SNES when Emulator is SubBsnesCore subBsnesCore:
|
case VSystemID.Raw.SNES when Emulator is SubBsnesCore subBsnesCore:
|
||||||
SNESSubMenu.Text = subBsnesCore.IsSGB ? "&SGB" : "&SNES";
|
SNESSubMenu.Text = subBsnesCore.IsSGB ? "&SGB" : "&SNES";
|
||||||
SnesGfxDebuggerMenuItem.Visible = false;
|
|
||||||
SNESSubMenu.Visible = true;
|
SNESSubMenu.Visible = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private readonly List<DisplayTypeItem> displayTypeItems = new List<DisplayTypeItem>();
|
private readonly List<DisplayTypeItem> displayTypeItems = new List<DisplayTypeItem>();
|
||||||
|
|
||||||
[RequiredService]
|
[RequiredService]
|
||||||
private LibsnesCore Emulator { get; set; }
|
private IBSNESForGfxDebugger Emulator { get; set; }
|
||||||
|
|
||||||
[ConfigPersist]
|
[ConfigPersist]
|
||||||
public bool UseUserBackdropColor
|
public bool UseUserBackdropColor
|
||||||
|
@ -63,7 +63,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
displayTypeItems.Add(new DisplayTypeItem("Sprites", eDisplayType.Sprites));
|
displayTypeItems.Add(new DisplayTypeItem("Sprites", eDisplayType.Sprites));
|
||||||
displayTypeItems.Add(new DisplayTypeItem("OBJ", eDisplayType.OBJ));
|
displayTypeItems.Add(new DisplayTypeItem("OBJ", eDisplayType.OBJ));
|
||||||
|
|
||||||
displayTypeItems.Add(new DisplayTypeItem("BG1 Screen", eDisplayType.BG1));
|
displayTypeItems.Add(new DisplayTypeItem("BG1 Screen", eDisplayType.BG1));
|
||||||
displayTypeItems.Add(new DisplayTypeItem("BG2 Screen", eDisplayType.BG2));
|
displayTypeItems.Add(new DisplayTypeItem("BG2 Screen", eDisplayType.BG2));
|
||||||
displayTypeItems.Add(new DisplayTypeItem("BG3 Screen", eDisplayType.BG3));
|
displayTypeItems.Add(new DisplayTypeItem("BG3 Screen", eDisplayType.BG3));
|
||||||
|
@ -85,6 +85,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
var paletteTypeItems = new List<PaletteTypeItem>
|
var paletteTypeItems = new List<PaletteTypeItem>
|
||||||
{
|
{
|
||||||
|
// must be in same order as enum
|
||||||
new PaletteTypeItem("BizHawk", SnesColors.ColorType.BizHawk),
|
new PaletteTypeItem("BizHawk", SnesColors.ColorType.BizHawk),
|
||||||
new PaletteTypeItem("bsnes", SnesColors.ColorType.BSNES),
|
new PaletteTypeItem("bsnes", SnesColors.ColorType.BSNES),
|
||||||
new PaletteTypeItem("Snes9X", SnesColors.ColorType.Snes9x)
|
new PaletteTypeItem("Snes9X", SnesColors.ColorType.Snes9x)
|
||||||
|
@ -104,12 +105,14 @@ namespace BizHawk.Client.EmuHawk
|
||||||
UserBackdropColor = -1;
|
UserBackdropColor = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LibsnesCore currentSnesCore;
|
private IBSNESForGfxDebugger currentSnesCore;
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnClosed(e);
|
base.OnClosed(e);
|
||||||
currentSnesCore?.ScanlineHookManager.Unregister(this);
|
currentSnesCore?.ScanlineHookManager?.Unregister(this);
|
||||||
currentSnesCore = null;
|
currentSnesCore = null;
|
||||||
|
gd = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string FormatBpp(int bpp)
|
private string FormatBpp(int bpp)
|
||||||
|
@ -168,11 +171,12 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
if (currentSnesCore != Emulator)
|
if (currentSnesCore != Emulator)
|
||||||
{
|
{
|
||||||
currentSnesCore?.ScanlineHookManager.Unregister(this);
|
currentSnesCore?.ScanlineHookManager?.Unregister(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentSnesCore != Emulator && Emulator != null)
|
if (currentSnesCore != Emulator && Emulator != null)
|
||||||
{
|
{
|
||||||
|
gd = null;
|
||||||
suppression = true;
|
suppression = true;
|
||||||
comboPalette.SelectedValue = Emulator.CurrPalette;
|
comboPalette.SelectedValue = Emulator.CurrPalette;
|
||||||
RefreshBGENCheckStatesFromConfig();
|
RefreshBGENCheckStatesFromConfig();
|
||||||
|
@ -184,9 +188,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
if (currentSnesCore != null)
|
if (currentSnesCore != null)
|
||||||
{
|
{
|
||||||
if (Visible && checkScanlineControl.Checked)
|
if (Visible && checkScanlineControl.Checked)
|
||||||
currentSnesCore.ScanlineHookManager.Register(this, ScanlineHook);
|
currentSnesCore.ScanlineHookManager?.Register(this, ScanlineHook);
|
||||||
else
|
else
|
||||||
currentSnesCore.ScanlineHookManager.Unregister(this);
|
currentSnesCore.ScanlineHookManager?.Unregister(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +204,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SNESGraphicsDecoder gd;
|
private ISNESGraphicsDecoder gd;
|
||||||
private SNESGraphicsDecoder.ScreenInfo si;
|
private SNESGraphicsDecoder.ScreenInfo si;
|
||||||
private SNESGraphicsDecoder.TileEntry[] map;
|
private SNESGraphicsDecoder.TileEntry[] map;
|
||||||
private readonly byte[,] spriteMap = new byte[256, 224];
|
private readonly byte[,] spriteMap = new byte[256, 224];
|
||||||
|
@ -208,14 +212,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private void RegenerateData()
|
private void RegenerateData()
|
||||||
{
|
{
|
||||||
gd?.Dispose();
|
|
||||||
gd = null;
|
|
||||||
if (currentSnesCore == null) return;
|
if (currentSnesCore == null) return;
|
||||||
gd = NewDecoder();
|
gd ??= NewDecoder();
|
||||||
using (gd.EnterExit())
|
using (gd.EnterExit())
|
||||||
{
|
{
|
||||||
if (checkBackdropColor.Checked)
|
|
||||||
gd.SetBackColor(DecodeWinformsColorToSNES(pnBackdropColor.BackColor));
|
|
||||||
gd.CacheTiles();
|
gd.CacheTiles();
|
||||||
si = gd.ScanScreenInfo();
|
si = gd.ScanScreenInfo();
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
txtScreenCGADSUB_AddSub_Descr.Text = si.CGADSUB_AddSub == 1 ? "SUB" : "ADD";
|
txtScreenCGADSUB_AddSub_Descr.Text = si.CGADSUB_AddSub == 1 ? "SUB" : "ADD";
|
||||||
txtScreenCGADSUB_Half.Checked = si.CGADSUB_Half;
|
txtScreenCGADSUB_Half.Checked = si.CGADSUB_Half;
|
||||||
|
|
||||||
txtModeBits.Text = si.Mode.MODE.ToString();
|
txtModeBits.Text = si.Mode.ToString();
|
||||||
txtScreenBG1Bpp.Text = FormatBpp(si.BG.BG1.Bpp);
|
txtScreenBG1Bpp.Text = FormatBpp(si.BG.BG1.Bpp);
|
||||||
txtScreenBG2Bpp.Text = FormatBpp(si.BG.BG2.Bpp);
|
txtScreenBG2Bpp.Text = FormatBpp(si.BG.BG2.Bpp);
|
||||||
txtScreenBG3Bpp.Text = FormatBpp(si.BG.BG3.Bpp);
|
txtScreenBG3Bpp.Text = FormatBpp(si.BG.BG3.Bpp);
|
||||||
|
@ -303,7 +303,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
checkMathBG3.Checked = si.BG.BG3.MathEnabled;
|
checkMathBG3.Checked = si.BG.BG3.MathEnabled;
|
||||||
checkMathBG4.Checked = si.BG.BG4.MathEnabled;
|
checkMathBG4.Checked = si.BG.BG4.MathEnabled;
|
||||||
|
|
||||||
if (si.Mode.MODE == 1 && si.Mode1_BG3_Priority)
|
if (si.Mode == 1 && si.Mode1_BG3_Priority)
|
||||||
{
|
{
|
||||||
lblBG3.ForeColor = Color.Red;
|
lblBG3.ForeColor = Color.Red;
|
||||||
if (toolTip1.GetToolTip(lblBG3) != "Mode 1 BG3 priority toggle bit of $2105 is SET")
|
if (toolTip1.GetToolTip(lblBG3) != "Mode 1 BG3 priority toggle bit of $2105 is SET")
|
||||||
|
@ -370,7 +370,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
for (int y = 0; y < 224; y++) for (int x = 0; x < 256; x++) spriteMap[x, y] = 0xFF;
|
for (int y = 0; y < 224; y++) for (int x = 0; x < 256; x++) spriteMap[x, y] = 0xFF;
|
||||||
for(int i=127;i>=0;i--)
|
for(int i=127;i>=0;i--)
|
||||||
{
|
{
|
||||||
var oam = new SNESGraphicsDecoder.OAMInfo(gd, si, i);
|
var oam = gd.CreateOAMInfo(si, i);
|
||||||
gd.RenderSpriteToScreen(pixelptr, stride / 4, oam.X, oam.Y, si, i, oam, 256, 224, spriteMap);
|
gd.RenderSpriteToScreen(pixelptr, stride / 4, oam.X, oam.Y, si, i, oam, 256, 224, spriteMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,24 +379,24 @@ namespace BizHawk.Client.EmuHawk
|
||||||
allocate(128, 256);
|
allocate(128, 256);
|
||||||
int startTile;
|
int startTile;
|
||||||
startTile = si.OBJTable0Addr / 32;
|
startTile = si.OBJTable0Addr / 32;
|
||||||
gd.RenderTilesToScreen(pixelptr, 16, 16, stride / 4, 4, currPaletteSelection.start, startTile, 256, true);
|
gd.RenderTilesToScreen(pixelptr, stride / 4, 4, currPaletteSelection.start, startTile, 256);
|
||||||
startTile = si.OBJTable1Addr / 32;
|
startTile = si.OBJTable1Addr / 32;
|
||||||
gd.RenderTilesToScreen(pixelptr + (stride/4*8*16), 16, 16, stride / 4, 4, currPaletteSelection.start, startTile, 256, true);
|
gd.RenderTilesToScreen(pixelptr + (stride/4*8*16), stride / 4, 4, currPaletteSelection.start, startTile, 256);
|
||||||
}
|
}
|
||||||
if (selection == eDisplayType.Tiles2bpp)
|
if (selection == eDisplayType.Tiles2bpp)
|
||||||
{
|
{
|
||||||
allocate(512, 512);
|
allocate(512, 512);
|
||||||
gd.RenderTilesToScreen(pixelptr, 64, 64, stride / 4, 2, currPaletteSelection.start);
|
gd.RenderTilesToScreen(pixelptr, stride / 4, 2, currPaletteSelection.start);
|
||||||
}
|
}
|
||||||
if (selection == eDisplayType.Tiles4bpp)
|
if (selection == eDisplayType.Tiles4bpp)
|
||||||
{
|
{
|
||||||
allocate(512, 512);
|
allocate(512, 512);
|
||||||
gd.RenderTilesToScreen(pixelptr, 64, 32, stride / 4, 4, currPaletteSelection.start);
|
gd.RenderTilesToScreen(pixelptr, stride / 4, 4, currPaletteSelection.start);
|
||||||
}
|
}
|
||||||
if (selection == eDisplayType.Tiles8bpp)
|
if (selection == eDisplayType.Tiles8bpp)
|
||||||
{
|
{
|
||||||
allocate(256, 256);
|
allocate(256, 256);
|
||||||
gd.RenderTilesToScreen(pixelptr, 32, 32, stride / 4, 8, currPaletteSelection.start);
|
gd.RenderTilesToScreen(pixelptr, stride / 4, 8, currPaletteSelection.start);
|
||||||
}
|
}
|
||||||
if (selection == eDisplayType.TilesMode7)
|
if (selection == eDisplayType.TilesMode7)
|
||||||
{
|
{
|
||||||
|
@ -431,7 +431,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
bool DirectColor = si.CGWSEL_DirectColor && bg.Bpp == 8; //any exceptions?
|
bool DirectColor = si.CGWSEL_DirectColor && bg.Bpp == 8; //any exceptions?
|
||||||
int numPixels = 0;
|
int numPixels = 0;
|
||||||
//TODO - could use BGMode property on BG... too much chaos to deal with it now
|
//TODO - could use BGMode property on BG... too much chaos to deal with it now
|
||||||
if (si.Mode.MODE == 7)
|
if (si.Mode == 7)
|
||||||
{
|
{
|
||||||
bool mode7 = bgnum == 1;
|
bool mode7 = bgnum == 1;
|
||||||
bool mode7extbg = (bgnum == 2 && si.SETINI_Mode7ExtBG);
|
bool mode7extbg = (bgnum == 2 && si.SETINI_Mode7ExtBG);
|
||||||
|
@ -499,7 +499,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
default: throw new InvalidOperationException();
|
default: throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DisplayTypeItem
|
private class DisplayTypeItem
|
||||||
{
|
{
|
||||||
public eDisplayType Type { get; }
|
public eDisplayType Type { get; }
|
||||||
|
@ -533,6 +533,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private void SNESGraphicsDebugger_Load(object sender, EventArgs e)
|
private void SNESGraphicsDebugger_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
currentSnesCore = Emulator;
|
||||||
|
gd = NewDecoder();
|
||||||
|
|
||||||
if (UserBackdropColor != -1)
|
if (UserBackdropColor != -1)
|
||||||
{
|
{
|
||||||
pnBackdropColor.BackColor = Color.FromArgb(UserBackdropColor);
|
pnBackdropColor.BackColor = Color.FromArgb(UserBackdropColor);
|
||||||
|
@ -540,6 +543,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
if (checkBackdropColor.Checked)
|
if (checkBackdropColor.Checked)
|
||||||
{
|
{
|
||||||
SyncBackdropColor();
|
SyncBackdropColor();
|
||||||
|
gd.SetBackColor(DecodeWinformsColorToSNES(pnBackdropColor.BackColor));
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateToolsLoadstate();
|
UpdateToolsLoadstate();
|
||||||
|
@ -639,16 +643,14 @@ namespace BizHawk.Client.EmuHawk
|
||||||
ret.start = 0;
|
ret.start = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.size = 1 << bpp;
|
ret.size = 1 << bpp;
|
||||||
ret.start = colorSelection & (~(ret.size - 1));
|
ret.start = colorSelection & (~(ret.size - 1));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SNESGraphicsDecoder NewDecoder()
|
private ISNESGraphicsDecoder NewDecoder()
|
||||||
{
|
=> currentSnesCore?.CreateGraphicsDecoder();
|
||||||
return currentSnesCore != null ? new SNESGraphicsDecoder(currentSnesCore.Api, currentSnesCore.CurrPalette) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderPalette()
|
private void RenderPalette()
|
||||||
{
|
{
|
||||||
|
@ -713,13 +715,13 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private void UpdateOBJDetails()
|
private void UpdateOBJDetails()
|
||||||
{
|
{
|
||||||
if (currObjDataState == null) return;
|
if (currObjDataState == null) return;
|
||||||
var oam = new SNESGraphicsDecoder.OAMInfo(gd, si, currObjDataState.Number);
|
var oam = gd.CreateOAMInfo(si, currObjDataState.Number);
|
||||||
txtObjNumber.Text = $"#${currObjDataState.Number:X2}";
|
txtObjNumber.Text = $"#${currObjDataState.Number:X2}";
|
||||||
txtObjCoord.Text = $"({oam.X}, {oam.Y})";
|
txtObjCoord.Text = $"({oam.X}, {oam.Y})";
|
||||||
cbObjHFlip.Checked = oam.HFlip;
|
cbObjHFlip.Checked = oam.HFlip;
|
||||||
cbObjVFlip.Checked = oam.VFlip;
|
cbObjVFlip.Checked = oam.VFlip;
|
||||||
cbObjLarge.Checked = oam.Size == 1;
|
cbObjLarge.Checked = oam.Size;
|
||||||
txtObjSize.Text = SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, oam.Size].ToString();
|
txtObjSize.Text = SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, oam.Size ? 1 : 0].ToString();
|
||||||
txtObjPriority.Text = oam.Priority.ToString();
|
txtObjPriority.Text = oam.Priority.ToString();
|
||||||
txtObjPalette.Text = oam.Palette.ToString();
|
txtObjPalette.Text = oam.Palette.ToString();
|
||||||
txtObjPaletteMemo.Text = $"${oam.Palette * 16 + 128:X2}";
|
txtObjPaletteMemo.Text = $"${oam.Palette * 16 + 128:X2}";
|
||||||
|
@ -874,7 +876,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
if (tp == tpPalette) groupFreeze.Text = "Freeze - Color";
|
if (tp == tpPalette) groupFreeze.Text = "Freeze - Color";
|
||||||
if (tp == tpTile) groupFreeze.Text = "Freeze - Tile";
|
if (tp == tpTile) groupFreeze.Text = "Freeze - Tile";
|
||||||
if (tp == tpOBJ) groupFreeze.Text = "Freeze - OBJ";
|
if (tp == tpOBJ) groupFreeze.Text = "Freeze - OBJ";
|
||||||
|
|
||||||
groupFreeze.ResumeLayout();
|
groupFreeze.ResumeLayout();
|
||||||
|
|
||||||
Win32Imports.SendMessage(groupFreeze.Handle, 11, (IntPtr)1, IntPtr.Zero); //WM_SETREDRAW true
|
Win32Imports.SendMessage(groupFreeze.Handle, 11, (IntPtr)1, IntPtr.Zero); //WM_SETREDRAW true
|
||||||
|
@ -981,9 +983,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
//render an obj tile
|
//render an obj tile
|
||||||
int tile = currTileDataState.Address / 32;
|
int tile = currTileDataState.Address / 32;
|
||||||
gd.RenderTilesToScreen((int*)bmpdata.Scan0, 1, 1, bmpdata.Stride / 4, bpp, currPaletteSelection.start, tile, 1);
|
gd.RenderTilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, bpp, currPaletteSelection.start, tile, 1);
|
||||||
}
|
}
|
||||||
else gd.RenderTilesToScreen((int*)bmpdata.Scan0, 1, 1, bmpdata.Stride / 4, bpp, currPaletteSelection.start, currTileDataState.Tile, 1);
|
else gd.RenderTilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, bpp, currPaletteSelection.start, currTileDataState.Tile, 1);
|
||||||
|
|
||||||
bmp.UnlockBits(bmpdata);
|
bmp.UnlockBits(bmpdata);
|
||||||
viewerTile.SetBitmap(bmp);
|
viewerTile.SetBitmap(bmp);
|
||||||
|
@ -1056,7 +1058,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
int ox = px / si.ObjSizeBounds.Width;
|
int ox = px / si.ObjSizeBounds.Width;
|
||||||
int oy = py / si.ObjSizeBounds.Height;
|
int oy = py / si.ObjSizeBounds.Height;
|
||||||
|
|
||||||
if (!0.RangeTo(7).Contains(ox) || !0.RangeTo(15).Contains(oy)) return;
|
if (!0.RangeTo(7).Contains(ox) || !0.RangeTo(15).Contains(oy)) return;
|
||||||
|
|
||||||
int objNum = oy * 8 + ox;
|
int objNum = oy * 8 + ox;
|
||||||
|
@ -1195,6 +1197,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private void checkBackdropColor_CheckedChanged(object sender, EventArgs e)
|
private void checkBackdropColor_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SyncBackdropColor();
|
SyncBackdropColor();
|
||||||
|
if (checkBackdropColor.Checked)
|
||||||
|
gd?.SetBackColor(DecodeWinformsColorToSNES(pnBackdropColor.BackColor));
|
||||||
|
else
|
||||||
|
gd?.SetBackColor();
|
||||||
RegenerateData();
|
RegenerateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1265,13 +1271,21 @@ namespace BizHawk.Client.EmuHawk
|
||||||
if (suppression) return;
|
if (suppression) return;
|
||||||
var pal = (SnesColors.ColorType)comboPalette.SelectedValue;
|
var pal = (SnesColors.ColorType)comboPalette.SelectedValue;
|
||||||
Console.WriteLine("set {0}", pal);
|
Console.WriteLine("set {0}", pal);
|
||||||
var s = Emulator.GetSettings();
|
try
|
||||||
s.Palette = pal.ToString();
|
{
|
||||||
currentSnesCore?.PutSettings(s);
|
currentSnesCore?.SetPalette(pal);
|
||||||
|
}
|
||||||
|
catch (NotImplementedException)
|
||||||
|
{
|
||||||
|
comboPalette.Enabled = false;
|
||||||
|
}
|
||||||
RegenerateData();
|
RegenerateData();
|
||||||
RenderView();
|
using (gd.EnterExit())
|
||||||
RenderPalette();
|
{
|
||||||
RenderTileView();
|
RenderView();
|
||||||
|
RenderPalette();
|
||||||
|
RenderTileView();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshBGENCheckStatesFromConfig()
|
private void RefreshBGENCheckStatesFromConfig()
|
||||||
|
|
|
@ -33,6 +33,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
[BizImport(CallingConvention.Cdecl)]
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
public abstract void* snes_get_memory_region(int id, out int size, out int wordSize);
|
public abstract void* snes_get_memory_region(int id, out int size, out int wordSize);
|
||||||
[BizImport(CallingConvention.Cdecl)]
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
|
public abstract int snes_peek_logical_register(BsnesApi.SNES_REGISTER register);
|
||||||
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
public abstract byte snes_bus_read(uint address);
|
public abstract byte snes_bus_read(uint address);
|
||||||
[BizImport(CallingConvention.Cdecl)]
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
public abstract void snes_bus_write(uint address, byte value);
|
public abstract void snes_bus_write(uint address, byte value);
|
||||||
|
|
|
@ -2,6 +2,91 @@
|
||||||
{
|
{
|
||||||
public partial class BsnesApi
|
public partial class BsnesApi
|
||||||
{
|
{
|
||||||
|
public enum SNES_REGISTER {
|
||||||
|
//$2105
|
||||||
|
BG_MODE,
|
||||||
|
BG3_PRIORITY,
|
||||||
|
BG1_TILESIZE,
|
||||||
|
BG2_TILESIZE,
|
||||||
|
BG3_TILESIZE,
|
||||||
|
BG4_TILESIZE,
|
||||||
|
//$2107
|
||||||
|
BG1_SCADDR,
|
||||||
|
BG1_SCSIZE,
|
||||||
|
//$2108
|
||||||
|
BG2_SCADDR,
|
||||||
|
BG2_SCSIZE,
|
||||||
|
//$2109,
|
||||||
|
BG3_SCADDR,
|
||||||
|
BG3_SCSIZE,
|
||||||
|
//$210A
|
||||||
|
BG4_SCADDR,
|
||||||
|
BG4_SCSIZE,
|
||||||
|
//$210B
|
||||||
|
BG1_TDADDR,
|
||||||
|
BG2_TDADDR,
|
||||||
|
//$210C
|
||||||
|
BG3_TDADDR,
|
||||||
|
BG4_TDADDR,
|
||||||
|
//$2133 SETINI
|
||||||
|
SETINI_MODE7_EXTBG,
|
||||||
|
SETINI_HIRES,
|
||||||
|
SETINI_OVERSCAN,
|
||||||
|
SETINI_OBJ_INTERLACE,
|
||||||
|
SETINI_SCREEN_INTERLACE,
|
||||||
|
//$2130 CGWSEL
|
||||||
|
CGWSEL_COLORMASK,
|
||||||
|
CGWSEL_COLORSUBMASK,
|
||||||
|
CGWSEL_ADDSUBMODE,
|
||||||
|
CGWSEL_DIRECTCOLOR,
|
||||||
|
//$2101 OBSEL
|
||||||
|
OBSEL_NAMEBASE,
|
||||||
|
OBSEL_NAMESEL,
|
||||||
|
OBSEL_SIZE,
|
||||||
|
//$2131 CGADSUB
|
||||||
|
CGADDSUB_MODE,
|
||||||
|
CGADDSUB_HALF,
|
||||||
|
CGADDSUB_BG4,
|
||||||
|
CGADDSUB_BG3,
|
||||||
|
CGADDSUB_BG2,
|
||||||
|
CGADDSUB_BG1,
|
||||||
|
CGADDSUB_OBJ,
|
||||||
|
CGADDSUB_BACKDROP,
|
||||||
|
//$212C TM
|
||||||
|
TM_BG1,
|
||||||
|
TM_BG2,
|
||||||
|
TM_BG3,
|
||||||
|
TM_BG4,
|
||||||
|
TM_OBJ,
|
||||||
|
//$212D TM
|
||||||
|
TS_BG1,
|
||||||
|
TS_BG2,
|
||||||
|
TS_BG3,
|
||||||
|
TS_BG4,
|
||||||
|
TS_OBJ,
|
||||||
|
//Mode7 regs
|
||||||
|
M7SEL_REPEAT,
|
||||||
|
M7SEL_HFLIP,
|
||||||
|
M7SEL_VFLIP,
|
||||||
|
M7A,
|
||||||
|
M7B,
|
||||||
|
M7C,
|
||||||
|
M7D,
|
||||||
|
M7X,
|
||||||
|
M7Y,
|
||||||
|
//BG scroll regs
|
||||||
|
BG1HOFS,
|
||||||
|
BG1VOFS,
|
||||||
|
BG2HOFS,
|
||||||
|
BG2VOFS,
|
||||||
|
BG3HOFS,
|
||||||
|
BG3VOFS,
|
||||||
|
BG4HOFS,
|
||||||
|
BG4VOFS,
|
||||||
|
M7HOFS,
|
||||||
|
M7VOFS
|
||||||
|
}
|
||||||
|
|
||||||
public enum SNES_MEMORY
|
public enum SNES_MEMORY
|
||||||
{
|
{
|
||||||
CARTRIDGE_RAM,
|
CARTRIDGE_RAM,
|
||||||
|
@ -18,7 +103,7 @@
|
||||||
WRAM,
|
WRAM,
|
||||||
APURAM,
|
APURAM,
|
||||||
VRAM,
|
VRAM,
|
||||||
// OAM, // needs some work in the core probably? or we return an objects pointer
|
OBJECTS,
|
||||||
CGRAM
|
CGRAM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
return _settings.Clone();
|
return _settings.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SNES.IBSNESForGfxDebugger.SettingsObj SNES.IBSNESForGfxDebugger.GetSettings()
|
||||||
|
=> GetSettings();
|
||||||
|
|
||||||
public SnesSyncSettings GetSyncSettings()
|
public SnesSyncSettings GetSyncSettings()
|
||||||
{
|
{
|
||||||
return _syncSettings.Clone();
|
return _syncSettings.Clone();
|
||||||
|
@ -21,6 +24,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
return PutSettingsDirtyBits.None;
|
return PutSettingsDirtyBits.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SNES.IBSNESForGfxDebugger.PutSettings(SNES.IBSNESForGfxDebugger.SettingsObj s)
|
||||||
|
=> PutSettings((SnesSettings) s);
|
||||||
|
|
||||||
public PutSettingsDirtyBits PutSyncSettings(SnesSyncSettings o)
|
public PutSettingsDirtyBits PutSyncSettings(SnesSyncSettings o)
|
||||||
{
|
{
|
||||||
bool ret = o.LeftPort != _syncSettings.LeftPort
|
bool ret = o.LeftPort != _syncSettings.LeftPort
|
||||||
|
@ -41,7 +47,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
private SnesSettings _settings;
|
private SnesSettings _settings;
|
||||||
private SnesSyncSettings _syncSettings;
|
private SnesSyncSettings _syncSettings;
|
||||||
|
|
||||||
public class SnesSettings
|
public class SnesSettings : SNES.IBSNESForGfxDebugger.SettingsObj
|
||||||
{
|
{
|
||||||
public bool ShowBG1_0 { get; set; } = true;
|
public bool ShowBG1_0 { get; set; } = true;
|
||||||
public bool ShowBG2_0 { get; set; } = true;
|
public bool ShowBG2_0 { get; set; } = true;
|
||||||
|
|
|
@ -4,6 +4,7 @@ using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Common.Base_Implementations;
|
using BizHawk.Emulation.Common.Base_Implementations;
|
||||||
using BizHawk.Emulation.Cores.Components.W65816;
|
using BizHawk.Emulation.Cores.Components.W65816;
|
||||||
|
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||||
|
|
||||||
// http://wiki.superfamicom.org/snes/show/Backgrounds
|
// http://wiki.superfamicom.org/snes/show/Backgrounds
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
{
|
{
|
||||||
[PortedCore(CoreNames.Bsnes115, "bsnes team", "v115+", "https://github.com/bsnes-emu/bsnes")]
|
[PortedCore(CoreNames.Bsnes115, "bsnes team", "v115+", "https://github.com/bsnes-emu/bsnes")]
|
||||||
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
|
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
|
||||||
public unsafe partial class BsnesCore : IEmulator, IDebuggable, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>
|
public unsafe partial class BsnesCore : IEmulator, IDebuggable, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>, IBSNESForGfxDebugger
|
||||||
{
|
{
|
||||||
[CoreConstructor(VSystemID.Raw.SGB)]
|
[CoreConstructor(VSystemID.Raw.SGB)]
|
||||||
[CoreConstructor(VSystemID.Raw.SNES)]
|
[CoreConstructor(VSystemID.Raw.SNES)]
|
||||||
|
@ -232,6 +233,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SnesColors.ColorType CurrPalette => SnesColors.ColorType.BSNES;
|
||||||
|
|
||||||
|
public void SetPalette(SnesColors.ColorType colorType)
|
||||||
|
{
|
||||||
|
if (colorType != SnesColors.ColorType.BSNES)
|
||||||
|
throw new NotImplementedException("This core does not currently support different palettes.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISNESGraphicsDecoder CreateGraphicsDecoder() => new SNESGraphicsDecoder(Api);
|
||||||
|
|
||||||
|
public ScanlineHookManager ScanlineHookManager => null;
|
||||||
|
|
||||||
private void snes_video_refresh(ushort* data, int width, int height, int pitch)
|
private void snes_video_refresh(ushort* data, int width, int height, int pitch)
|
||||||
{
|
{
|
||||||
int widthMultiplier = 1;
|
int widthMultiplier = 1;
|
||||||
|
|
|
@ -0,0 +1,642 @@
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||||
|
using static BizHawk.Emulation.Cores.Nintendo.BSNES.BsnesApi.SNES_REGISTER;
|
||||||
|
using static BizHawk.Emulation.Cores.Nintendo.SNES.SNESGraphicsDecoder;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
|
{
|
||||||
|
public sealed unsafe class SNESGraphicsDecoder : ISNESGraphicsDecoder
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Object // size: 10 bytes; equivalent to the c++ version
|
||||||
|
{
|
||||||
|
public readonly ushort x;
|
||||||
|
public readonly byte y;
|
||||||
|
public readonly byte character;
|
||||||
|
public readonly bool nameSelect;
|
||||||
|
public readonly bool vflip;
|
||||||
|
public readonly bool hflip;
|
||||||
|
public readonly byte priority;
|
||||||
|
public readonly byte palette;
|
||||||
|
public readonly bool size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly BsnesApi _api;
|
||||||
|
private readonly byte* vram; // waterbox pointer, ALWAYS access with EnterExit()
|
||||||
|
private readonly Object* objects; // waterbox pointer, ALWAYS access with EnterExit()
|
||||||
|
private readonly ushort* cgram; // waterbox pointer, ALWAYS access with EnterExit()
|
||||||
|
private readonly byte[][] cachedTiles = new byte[5][];
|
||||||
|
private readonly int[] bppArrayIndex = { 0, 0, 0, 0, 1, 0, 0, 0, 2 };
|
||||||
|
|
||||||
|
private bool useBackColor;
|
||||||
|
private int backColor;
|
||||||
|
|
||||||
|
private readonly int[] palette = new int[32768];
|
||||||
|
private readonly short[] directColorTable = new short[256];
|
||||||
|
private void generate_palette()
|
||||||
|
{
|
||||||
|
const int a = 0xFF;
|
||||||
|
for (int color = 0; color < 32768; color++) {
|
||||||
|
int r = (color >> 10) & 31;
|
||||||
|
int g = (color >> 5) & 31;
|
||||||
|
int b = (color >> 0) & 31;
|
||||||
|
|
||||||
|
r = r << 3 | r >> 2; r = r << 8 | r << 0;
|
||||||
|
g = g << 3 | g >> 2; g = g << 8 | g << 0;
|
||||||
|
b = b << 3 | b >> 2; b = b << 8 | b << 0;
|
||||||
|
|
||||||
|
palette[color] = a << 24 | b >> 8 << 16 | g >> 8 << 8 | r >> 8 << 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generate_directColorTable()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
directColorTable[i] = (short)
|
||||||
|
( (i << 2 & 0x001c) //R
|
||||||
|
+ (i << 4 & 0x0380) //G
|
||||||
|
+ (i << 7 & 0x6000) ); //B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SNESGraphicsDecoder(BsnesApi api)
|
||||||
|
{
|
||||||
|
_api = api;
|
||||||
|
vram = (byte*)api.core.snes_get_memory_region((int)BsnesApi.SNES_MEMORY.VRAM, out _, out _);
|
||||||
|
objects = (Object*)api.core.snes_get_memory_region((int)BsnesApi.SNES_MEMORY.OBJECTS, out _, out _);
|
||||||
|
cgram = (ushort*)api.core.snes_get_memory_region((int)BsnesApi.SNES_MEMORY.CGRAM, out _, out _);
|
||||||
|
generate_palette();
|
||||||
|
generate_directColorTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CacheTiles()
|
||||||
|
{
|
||||||
|
CacheTiles2Bpp();
|
||||||
|
CacheTiles_Merge(4);
|
||||||
|
CacheTiles_Merge(8);
|
||||||
|
CacheTilesMode7();
|
||||||
|
CacheTilesMode7ExtBg();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheTiles2Bpp()
|
||||||
|
{
|
||||||
|
const int tileCount = 65536 / 8 / 2;
|
||||||
|
cachedTiles[0] ??= new byte[8 * 8 * tileCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < tileCount; i++)
|
||||||
|
{
|
||||||
|
int offset = 64 * i;
|
||||||
|
int addr = 16 * i;
|
||||||
|
const int stride = 8;
|
||||||
|
for (int y = 0; y < 8; y++)
|
||||||
|
{
|
||||||
|
byte val = vram[addr + 1];
|
||||||
|
for (int x = 0; x < 8; x++)
|
||||||
|
cachedTiles[0][offset + y * stride + x] = (byte)(val >> (7 - x) & 1);
|
||||||
|
val = vram[addr + 0];
|
||||||
|
for (int x = 0; x < 8; x++)
|
||||||
|
cachedTiles[0][offset + y * stride + x] = (byte)((cachedTiles[0][offset + y * stride + x] << 1) | (val >> (7 - x) & 1));
|
||||||
|
addr += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheTiles_Merge(int toBpp)
|
||||||
|
{
|
||||||
|
int shift = toBpp / 2;
|
||||||
|
int tileCount = 8192 / toBpp;
|
||||||
|
int destinationIndex = bppArrayIndex[toBpp];
|
||||||
|
cachedTiles[destinationIndex] ??= new byte[8 * 8 * tileCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < tileCount; i++)
|
||||||
|
{
|
||||||
|
int srcAddr = 128 * i;
|
||||||
|
int dstAddr = 64 * i;
|
||||||
|
for (int p = 0; p < 64; p++)
|
||||||
|
{
|
||||||
|
int tileA = cachedTiles[destinationIndex - 1][srcAddr + p];
|
||||||
|
int tileB = cachedTiles[destinationIndex - 1][srcAddr + p + 64];
|
||||||
|
cachedTiles[destinationIndex][dstAddr + p] = (byte)(tileA | (tileB << shift));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheTilesMode7()
|
||||||
|
{
|
||||||
|
const int tileCount = 256;
|
||||||
|
const int pixelCount = 8 * 8 * tileCount;
|
||||||
|
cachedTiles[3] ??= new byte[pixelCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < pixelCount; i++)
|
||||||
|
cachedTiles[3][i] = vram[2*i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheTilesMode7ExtBg()
|
||||||
|
{
|
||||||
|
const int tileCount = 256;
|
||||||
|
const int pixelCount = 8 * 8 * tileCount;
|
||||||
|
cachedTiles[4] ??= new byte[pixelCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < pixelCount; i++)
|
||||||
|
cachedTiles[4][i] = (byte)(cachedTiles[3][i] & 0x7F);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Colorize(int rgb555)
|
||||||
|
{
|
||||||
|
return palette[rgb555];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Colorize(int* buf, int offset, int numpixels)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numpixels; i++)
|
||||||
|
{
|
||||||
|
buf[offset + i] = palette[buf[offset + i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISNESGraphicsDecoder.OAMInfo CreateOAMInfo(ScreenInfo si, int num) => new OAMInfo(objects, si, num);
|
||||||
|
|
||||||
|
public void DecodeBG(
|
||||||
|
int* screen,
|
||||||
|
int stride, TileEntry[] map,
|
||||||
|
int tiledataBaseAddr, ScreenSize size,
|
||||||
|
int bpp,
|
||||||
|
int tilesize,
|
||||||
|
int paletteStart)
|
||||||
|
{
|
||||||
|
//emergency backstop. this can only happen if we're displaying an unavailable BG or other similar such value
|
||||||
|
if (bpp == 0) return;
|
||||||
|
|
||||||
|
int ncolors = 1 << bpp;
|
||||||
|
|
||||||
|
var dims = SizeInTilesForBGSize(size);
|
||||||
|
int count8x8 = tilesize / 8;
|
||||||
|
int tileSizeBytes = 8 * bpp;
|
||||||
|
int baseTileNum = tiledataBaseAddr / tileSizeBytes;
|
||||||
|
byte[] tileCache = cachedTiles[bppArrayIndex[bpp]];
|
||||||
|
int tileCacheMask = tileCache.Length - 1;
|
||||||
|
|
||||||
|
for (int mty = 0; mty < dims.Height; mty++)
|
||||||
|
for (int mtx = 0; mtx < dims.Width; mtx++)
|
||||||
|
for (int tx = 0; tx < count8x8; tx++)
|
||||||
|
for (int ty = 0; ty < count8x8; ty++)
|
||||||
|
{
|
||||||
|
int mapIndex = mty * dims.Width + mtx;
|
||||||
|
var te = map[mapIndex];
|
||||||
|
|
||||||
|
//apply metatile flipping
|
||||||
|
int tnx = tx, tny = ty;
|
||||||
|
if (tilesize == 16)
|
||||||
|
{
|
||||||
|
if ((te.flags & TileEntryFlags.Horz) != 0) tnx = 1 - tnx;
|
||||||
|
if ((te.flags & TileEntryFlags.Vert) != 0) tny = 1 - tny;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tileNum = te.tilenum + tnx + tny * 16 + baseTileNum;
|
||||||
|
int srcOfs = tileNum * 64;
|
||||||
|
|
||||||
|
for (int y = 0; y < 8; y++)
|
||||||
|
for (int x = 0; x < 8; x++)
|
||||||
|
{
|
||||||
|
int px = x;
|
||||||
|
int py = y;
|
||||||
|
if ((te.flags & TileEntryFlags.Horz) != 0) px = 7 - x;
|
||||||
|
if ((te.flags & TileEntryFlags.Vert) != 0) 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 & tileCacheMask];
|
||||||
|
srcOfs++;
|
||||||
|
// if (color != 0)
|
||||||
|
// {
|
||||||
|
color += te.palette * ncolors;
|
||||||
|
color += paletteStart;
|
||||||
|
// }
|
||||||
|
|
||||||
|
screen[dstOfs] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DecodeMode7BG(int* screen, int stride, bool extBg)
|
||||||
|
{
|
||||||
|
byte[] cachedTileBuffer = cachedTiles[extBg ? 4 : 3];
|
||||||
|
for (int ty = 0, tidx = 0; ty < 128; ty++)
|
||||||
|
for (int tx = 0; tx < 128; tx++, tidx++)
|
||||||
|
{
|
||||||
|
int tileEntry = vram[tidx * 2];
|
||||||
|
int src = tileEntry * 64;
|
||||||
|
for (int py = 0; py < 8; py++)
|
||||||
|
for (int px = 0; px < 8; px++)
|
||||||
|
{
|
||||||
|
int dst = (ty * 8 + py) * stride + (tx * 8 + px);
|
||||||
|
int srcData = cachedTileBuffer[src++];
|
||||||
|
screen[dst] = srcData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DirectColorify(int* screen, int numPixels)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numPixels; i++)
|
||||||
|
{
|
||||||
|
screen[i] = directColorTable[screen[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enter()
|
||||||
|
=> _api.Enter();
|
||||||
|
|
||||||
|
public void Exit()
|
||||||
|
=> _api.Exit();
|
||||||
|
|
||||||
|
public TileEntry[] FetchMode7Tilemap()
|
||||||
|
{
|
||||||
|
var buf = new TileEntry[128*128];
|
||||||
|
for (int tidx = 0; tidx < 128 * 128; tidx++)
|
||||||
|
{
|
||||||
|
buf[tidx].address = tidx * 2;
|
||||||
|
buf[tidx].tilenum = vram[tidx * 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TileEntry[] FetchTilemap(int addr, ScreenSize size)
|
||||||
|
{
|
||||||
|
Dimensions blockDimensions = SizeInBlocksForBGSize(size);
|
||||||
|
int realWidth = blockDimensions.Width * 32;
|
||||||
|
int realHeight = blockDimensions.Height * 32;
|
||||||
|
TileEntry[] buf = new TileEntry[realWidth*realHeight];
|
||||||
|
|
||||||
|
for (int by = 0; by < blockDimensions.Height; by++)
|
||||||
|
for (int bx = 0; bx < blockDimensions.Width; bx++)
|
||||||
|
for (int y = 0; y < 32; y++)
|
||||||
|
for (int x = 0; x < 32; x++)
|
||||||
|
{
|
||||||
|
int idx = (by * 32 + y) * realWidth + 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);
|
||||||
|
buf[idx].address = addr;
|
||||||
|
addr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] GetPalette()
|
||||||
|
{
|
||||||
|
int[] ret = new int[256];
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
ret[i] = cgram[i] & 0x7FFF;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Paletteize(int* buf, int offset, int startcolor, int numpixels)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numpixels; i++)
|
||||||
|
{
|
||||||
|
int entry = buf[offset + i];
|
||||||
|
int color = entry == 0 && useBackColor ? backColor : cgram[startcolor + entry] & 0x7FFF;
|
||||||
|
|
||||||
|
buf[offset + i] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenderMode7TilesToScreen(
|
||||||
|
int* screen,
|
||||||
|
int stride,
|
||||||
|
bool ext,
|
||||||
|
bool directColor,
|
||||||
|
int tilesWide,
|
||||||
|
int startTile,
|
||||||
|
int numTiles)
|
||||||
|
{
|
||||||
|
byte[] cachedTileBuffer = cachedTiles[ext ? 4 : 3];
|
||||||
|
for (int i = 0; i < numTiles; i++)
|
||||||
|
{
|
||||||
|
int targetYPos = i / tilesWide * stride * 8;
|
||||||
|
int targetXPos = i % tilesWide * 8;
|
||||||
|
int destinationOffset = targetYPos + targetXPos;
|
||||||
|
int sourceOffset = (startTile + i) * 64;
|
||||||
|
for (int y = 0; y < 8; y++)
|
||||||
|
for (int x = 0; x < 8; x++)
|
||||||
|
{
|
||||||
|
screen[destinationOffset + y * stride + x] = cachedTileBuffer[sourceOffset++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numPixels = numTiles * 8 * 8;
|
||||||
|
if (directColor) DirectColorify(screen, numPixels);
|
||||||
|
else Paletteize(screen, 0, 0, numPixels);
|
||||||
|
Colorize(screen, 0, numPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenderSpriteToScreen(
|
||||||
|
int* screen,
|
||||||
|
int stride,
|
||||||
|
int destx,
|
||||||
|
int desty, ScreenInfo si,
|
||||||
|
int spritenum,
|
||||||
|
ISNESGraphicsDecoder.OAMInfo oam,
|
||||||
|
int xlimit,
|
||||||
|
int ylimit,
|
||||||
|
byte[,] spriteMap)
|
||||||
|
{
|
||||||
|
oam ??= new OAMInfo(objects, si, spritenum);
|
||||||
|
Size dim = ObjSizes[si.OBSEL_Size, oam.Size ? 1 : 0];
|
||||||
|
|
||||||
|
byte[] cachedTileBuffer = cachedTiles[bppArrayIndex[4]];
|
||||||
|
|
||||||
|
int baseaddr = oam.Table ? si.OBJTable1Addr : si.OBJTable0Addr;
|
||||||
|
|
||||||
|
//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 dy, dx;
|
||||||
|
|
||||||
|
if (oam.HFlip)
|
||||||
|
dx = dim.Width - 1 - ox;
|
||||||
|
else dx = ox;
|
||||||
|
if (oam.VFlip)
|
||||||
|
dy = dim.Height - 1 - oy;
|
||||||
|
else dy = oy;
|
||||||
|
|
||||||
|
dx += destx;
|
||||||
|
dy += desty;
|
||||||
|
|
||||||
|
if(dx>=xlimit || dy>=ylimit || dx<0 || dy<0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int col = (bcol + (ox >> 3)) & 0xF;
|
||||||
|
int row = (brow + (oy >> 3)) & 0xF;
|
||||||
|
int sx = ox & 0x7;
|
||||||
|
int sy = oy & 0x7;
|
||||||
|
|
||||||
|
int addr = baseaddr*2 + (row * 16 + col) * 64;
|
||||||
|
addr += sy * 8 + sx;
|
||||||
|
|
||||||
|
int dofs = stride*dy+dx;
|
||||||
|
int color = cachedTileBuffer[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 RenderTilesToScreen(
|
||||||
|
int* screen,
|
||||||
|
int stride,
|
||||||
|
int bpp,
|
||||||
|
int startcolor,
|
||||||
|
int startTile,
|
||||||
|
int numTiles)
|
||||||
|
{
|
||||||
|
if (numTiles == -1)
|
||||||
|
numTiles = 8192 / bpp;
|
||||||
|
byte[] cachedTileBuffer = cachedTiles[bppArrayIndex[bpp]];
|
||||||
|
int tilesPerRow = stride / 8;
|
||||||
|
for (int i = 0; i < numTiles; i++)
|
||||||
|
{
|
||||||
|
int targetYPos = i / tilesPerRow * stride * 8;
|
||||||
|
int targetXPos = i % tilesPerRow * 8;
|
||||||
|
int destinationOffset = targetYPos + targetXPos;
|
||||||
|
int sourceOffset = (startTile + i) * 64;
|
||||||
|
for (int y = 0; y < 8; y++)
|
||||||
|
for (int x = 0; x < 8; x++)
|
||||||
|
{
|
||||||
|
screen[destinationOffset + y * stride + x] = cachedTileBuffer[sourceOffset++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numPixels = numTiles * 8 * 8;
|
||||||
|
Paletteize(screen, 0, startcolor, numPixels);
|
||||||
|
Colorize(screen, 0, numPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScreenInfo ScanScreenInfo()
|
||||||
|
{
|
||||||
|
int OBSEL_NameSel = _api.core.snes_peek_logical_register(OBSEL_NAMESEL);
|
||||||
|
int OBSEL_NameBase = _api.core.snes_peek_logical_register(OBSEL_NAMEBASE);
|
||||||
|
|
||||||
|
ScreenInfo screenInfo = new()
|
||||||
|
{
|
||||||
|
Mode = _api.core.snes_peek_logical_register(BG_MODE),
|
||||||
|
Mode1_BG3_Priority = _api.core.snes_peek_logical_register(BG3_PRIORITY) == 1,
|
||||||
|
SETINI_Mode7ExtBG = _api.core.snes_peek_logical_register(SETINI_MODE7_EXTBG) == 1,
|
||||||
|
SETINI_HiRes = _api.core.snes_peek_logical_register(SETINI_HIRES) == 1,
|
||||||
|
SETINI_Overscan = _api.core.snes_peek_logical_register(SETINI_OVERSCAN) == 1,
|
||||||
|
SETINI_ObjInterlace = _api.core.snes_peek_logical_register(SETINI_OBJ_INTERLACE) == 1,
|
||||||
|
SETINI_ScreenInterlace = _api.core.snes_peek_logical_register(SETINI_SCREEN_INTERLACE) == 1,
|
||||||
|
CGWSEL_ColorMask = _api.core.snes_peek_logical_register(CGWSEL_COLORMASK),
|
||||||
|
CGWSEL_ColorSubMask = _api.core.snes_peek_logical_register(CGWSEL_COLORSUBMASK),
|
||||||
|
CGWSEL_AddSubMode = _api.core.snes_peek_logical_register(CGWSEL_ADDSUBMODE),
|
||||||
|
CGWSEL_DirectColor = _api.core.snes_peek_logical_register(CGWSEL_DIRECTCOLOR) == 1,
|
||||||
|
CGADSUB_AddSub = _api.core.snes_peek_logical_register(CGADDSUB_MODE),
|
||||||
|
CGADSUB_Half = _api.core.snes_peek_logical_register(CGADDSUB_HALF) == 1,
|
||||||
|
OBSEL_Size = _api.core.snes_peek_logical_register(OBSEL_SIZE),
|
||||||
|
OBSEL_NameSel = OBSEL_NameSel,
|
||||||
|
OBSEL_NameBase = OBSEL_NameBase,
|
||||||
|
OBJTable0Addr = OBSEL_NameBase << 14,
|
||||||
|
OBJTable1Addr = ((OBSEL_NameBase << 14) + ((OBSEL_NameSel + 1) << 13)) & 0xFFFF,
|
||||||
|
OBJ_MainEnabled = _api.core.snes_peek_logical_register(TM_OBJ) == 1,
|
||||||
|
OBJ_SubEnabled = _api.core.snes_peek_logical_register(TS_OBJ) == 1,
|
||||||
|
OBJ_MathEnabled = _api.core.snes_peek_logical_register(CGADDSUB_OBJ) == 1,
|
||||||
|
BK_MathEnabled = _api.core.snes_peek_logical_register(CGADDSUB_BACKDROP) == 1,
|
||||||
|
M7HOFS = _api.core.snes_peek_logical_register(M7HOFS),
|
||||||
|
M7VOFS = _api.core.snes_peek_logical_register(M7VOFS),
|
||||||
|
M7A = _api.core.snes_peek_logical_register(M7A),
|
||||||
|
M7B = _api.core.snes_peek_logical_register(M7B),
|
||||||
|
M7C = _api.core.snes_peek_logical_register(M7C),
|
||||||
|
M7D = _api.core.snes_peek_logical_register(M7D),
|
||||||
|
M7X = _api.core.snes_peek_logical_register(M7X),
|
||||||
|
M7Y = _api.core.snes_peek_logical_register(M7Y),
|
||||||
|
M7SEL_REPEAT = _api.core.snes_peek_logical_register(M7SEL_REPEAT),
|
||||||
|
M7SEL_HFLIP = _api.core.snes_peek_logical_register(M7SEL_HFLIP) == 1,
|
||||||
|
M7SEL_VFLIP = _api.core.snes_peek_logical_register(M7SEL_VFLIP) == 1
|
||||||
|
};
|
||||||
|
|
||||||
|
screenInfo.ObjSizeBounds = ObjSizes[screenInfo.OBSEL_Size,1];
|
||||||
|
int square = Math.Max(screenInfo.ObjSizeBounds.Width, screenInfo.ObjSizeBounds.Height);
|
||||||
|
screenInfo.ObjSizeBoundsSquare = new Size(square, square);
|
||||||
|
|
||||||
|
screenInfo.BG.BG1.Bpp = ModeBpps[screenInfo.Mode, 0];
|
||||||
|
screenInfo.BG.BG2.Bpp = ModeBpps[screenInfo.Mode, 1];
|
||||||
|
screenInfo.BG.BG3.Bpp = ModeBpps[screenInfo.Mode, 2];
|
||||||
|
screenInfo.BG.BG4.Bpp = ModeBpps[screenInfo.Mode, 3];
|
||||||
|
|
||||||
|
//initial setting of mode type (derived from bpp table.. mode7 bg types will be fixed up later)
|
||||||
|
for (int i = 1; i <= 4; i++)
|
||||||
|
screenInfo.BG[i].BGMode = screenInfo.BG[i].Bpp == 0 ? BGMode.Unavailable : BGMode.Text;
|
||||||
|
|
||||||
|
screenInfo.BG.BG1.TILESIZE = _api.core.snes_peek_logical_register(BG1_TILESIZE);
|
||||||
|
screenInfo.BG.BG2.TILESIZE = _api.core.snes_peek_logical_register(BG2_TILESIZE);
|
||||||
|
screenInfo.BG.BG3.TILESIZE = _api.core.snes_peek_logical_register(BG3_TILESIZE);
|
||||||
|
screenInfo.BG.BG4.TILESIZE = _api.core.snes_peek_logical_register(BG4_TILESIZE);
|
||||||
|
|
||||||
|
screenInfo.BG.BG1.SCSIZE = _api.core.snes_peek_logical_register(BG1_SCSIZE);
|
||||||
|
screenInfo.BG.BG2.SCSIZE = _api.core.snes_peek_logical_register(BG2_SCSIZE);
|
||||||
|
screenInfo.BG.BG3.SCSIZE = _api.core.snes_peek_logical_register(BG3_SCSIZE);
|
||||||
|
screenInfo.BG.BG4.SCSIZE = _api.core.snes_peek_logical_register(BG4_SCSIZE);
|
||||||
|
screenInfo.BG.BG1.SCADDR = _api.core.snes_peek_logical_register(BG1_SCADDR);
|
||||||
|
screenInfo.BG.BG2.SCADDR = _api.core.snes_peek_logical_register(BG2_SCADDR);
|
||||||
|
screenInfo.BG.BG3.SCADDR = _api.core.snes_peek_logical_register(BG3_SCADDR);
|
||||||
|
screenInfo.BG.BG4.SCADDR = _api.core.snes_peek_logical_register(BG4_SCADDR);
|
||||||
|
screenInfo.BG.BG1.TDADDR = _api.core.snes_peek_logical_register(BG1_TDADDR);
|
||||||
|
screenInfo.BG.BG2.TDADDR = _api.core.snes_peek_logical_register(BG2_TDADDR);
|
||||||
|
screenInfo.BG.BG3.TDADDR = _api.core.snes_peek_logical_register(BG3_TDADDR);
|
||||||
|
screenInfo.BG.BG4.TDADDR = _api.core.snes_peek_logical_register(BG4_TDADDR);
|
||||||
|
|
||||||
|
screenInfo.BG.BG1.MainEnabled = _api.core.snes_peek_logical_register(TM_BG1) == 1;
|
||||||
|
screenInfo.BG.BG2.MainEnabled = _api.core.snes_peek_logical_register(TM_BG2) == 1;
|
||||||
|
screenInfo.BG.BG3.MainEnabled = _api.core.snes_peek_logical_register(TM_BG3) == 1;
|
||||||
|
screenInfo.BG.BG4.MainEnabled = _api.core.snes_peek_logical_register(TM_BG4) == 1;
|
||||||
|
screenInfo.BG.BG1.SubEnabled = _api.core.snes_peek_logical_register(TS_BG1) == 1;
|
||||||
|
screenInfo.BG.BG2.SubEnabled = _api.core.snes_peek_logical_register(TS_BG2) == 1;
|
||||||
|
screenInfo.BG.BG3.SubEnabled = _api.core.snes_peek_logical_register(TS_BG3) == 1;
|
||||||
|
screenInfo.BG.BG4.SubEnabled = _api.core.snes_peek_logical_register(TS_BG4) == 1;
|
||||||
|
screenInfo.BG.BG1.MathEnabled = _api.core.snes_peek_logical_register(CGADDSUB_BG1) == 1;
|
||||||
|
screenInfo.BG.BG2.MathEnabled = _api.core.snes_peek_logical_register(CGADDSUB_BG2) == 1;
|
||||||
|
screenInfo.BG.BG3.MathEnabled = _api.core.snes_peek_logical_register(CGADDSUB_BG3) == 1;
|
||||||
|
screenInfo.BG.BG4.MathEnabled = _api.core.snes_peek_logical_register(CGADDSUB_BG4) == 1;
|
||||||
|
|
||||||
|
screenInfo.BG.BG1.HOFS = _api.core.snes_peek_logical_register(BG1HOFS);
|
||||||
|
screenInfo.BG.BG1.VOFS = _api.core.snes_peek_logical_register(BG1VOFS);
|
||||||
|
screenInfo.BG.BG2.HOFS = _api.core.snes_peek_logical_register(BG2HOFS);
|
||||||
|
screenInfo.BG.BG2.VOFS = _api.core.snes_peek_logical_register(BG2VOFS);
|
||||||
|
screenInfo.BG.BG3.HOFS = _api.core.snes_peek_logical_register(BG3HOFS);
|
||||||
|
screenInfo.BG.BG3.VOFS = _api.core.snes_peek_logical_register(BG3VOFS);
|
||||||
|
screenInfo.BG.BG4.HOFS = _api.core.snes_peek_logical_register(BG4HOFS);
|
||||||
|
screenInfo.BG.BG4.VOFS = _api.core.snes_peek_logical_register(BG4VOFS);
|
||||||
|
|
||||||
|
for (int i = 1; i <= 4; i++)
|
||||||
|
{
|
||||||
|
screenInfo.BG[i].Mode = screenInfo.Mode;
|
||||||
|
screenInfo.BG[i].TiledataAddr = screenInfo.BG[i].TDADDR << 13;
|
||||||
|
screenInfo.BG[i].ScreenAddr = screenInfo.BG[i].SCADDR << 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fixup irregular things for mode 7
|
||||||
|
if (screenInfo.Mode == 7)
|
||||||
|
{
|
||||||
|
screenInfo.BG.BG1.TiledataAddr = 0;
|
||||||
|
screenInfo.BG.BG1.ScreenAddr = 0;
|
||||||
|
|
||||||
|
screenInfo.BG.BG1.BGMode = screenInfo.CGWSEL_DirectColor ? BGMode.Mode7DC : BGMode.Mode7;
|
||||||
|
|
||||||
|
if (screenInfo.SETINI_Mode7ExtBG)
|
||||||
|
{
|
||||||
|
screenInfo.BG.BG2.BGMode = BGMode.Mode7Ext;
|
||||||
|
screenInfo.BG.BG2.Bpp = 7;
|
||||||
|
screenInfo.BG.BG2.TiledataAddr = 0;
|
||||||
|
screenInfo.BG.BG2.ScreenAddr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//determine which colors each BG could use
|
||||||
|
switch (screenInfo.Mode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
screenInfo.BG.BG1.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
screenInfo.BG.BG2.PaletteSelection = new PaletteSelection(32, 32);
|
||||||
|
screenInfo.BG.BG3.PaletteSelection = new PaletteSelection(64, 32);
|
||||||
|
screenInfo.BG.BG4.PaletteSelection = new PaletteSelection(96, 32);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
screenInfo.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
screenInfo.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
screenInfo.BG.BG3.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
screenInfo.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
screenInfo.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
screenInfo.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
screenInfo.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
screenInfo.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 7:
|
||||||
|
screenInfo.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
||||||
|
screenInfo.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
screenInfo.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
screenInfo.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
screenInfo.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
||||||
|
screenInfo.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
screenInfo.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
screenInfo.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
screenInfo.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
screenInfo.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
screenInfo.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
screenInfo.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return screenInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBackColor(int snescol)
|
||||||
|
{
|
||||||
|
if (snescol == -1)
|
||||||
|
{
|
||||||
|
useBackColor = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
useBackColor = true;
|
||||||
|
backColor = snescol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class OAMInfo : ISNESGraphicsDecoder.OAMInfo
|
||||||
|
{
|
||||||
|
public ushort X { get; }
|
||||||
|
public byte Y { get; }
|
||||||
|
public int Tile { get; }
|
||||||
|
public bool Table { get; }
|
||||||
|
public int Palette { get; }
|
||||||
|
public byte Priority { get; }
|
||||||
|
public bool VFlip { get; }
|
||||||
|
public bool HFlip { get; }
|
||||||
|
public bool Size { get; }
|
||||||
|
public int Address { get; }
|
||||||
|
|
||||||
|
public unsafe OAMInfo(SNESGraphicsDecoder.Object* objects, ScreenInfo si, int index)
|
||||||
|
{
|
||||||
|
X = objects[index].x;
|
||||||
|
Y = objects[index].y;
|
||||||
|
Table = objects[index].nameSelect;
|
||||||
|
Palette = objects[index].palette;
|
||||||
|
Priority = objects[index].priority;
|
||||||
|
HFlip = objects[index].hflip;
|
||||||
|
VFlip = objects[index].vflip;
|
||||||
|
Size = objects[index].size;
|
||||||
|
byte character = objects[index].character;
|
||||||
|
Tile = character + (Table ? 256 : 0);
|
||||||
|
Address = character * 32 + (Table ? si.OBJTable1Addr : si.OBJTable0Addr);
|
||||||
|
Address &= 0xFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
{
|
{
|
||||||
|
@ -28,18 +29,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IMemoryDomains>());
|
ser.Register(_bsnesCore.ServiceProvider.GetService<IMemoryDomains>());
|
||||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IDisassemblable>());
|
ser.Register(_bsnesCore.ServiceProvider.GetService<IDisassemblable>());
|
||||||
ser.Register(_bsnesCore.ServiceProvider.GetService<ITraceable>());
|
ser.Register(_bsnesCore.ServiceProvider.GetService<ITraceable>());
|
||||||
|
ser.Register(_bsnesCore.ServiceProvider.GetService<IBSNESForGfxDebugger>());
|
||||||
if (IsSGB)
|
if (IsSGB)
|
||||||
{
|
{
|
||||||
// board info is only set in SGB mode
|
// board info is only set in SGB mode
|
||||||
ser.Register(_bsnesCore.ServiceProvider.GetService<IBoardInfo>());
|
ser.Register(_bsnesCore.ServiceProvider.GetService<IBoardInfo>());
|
||||||
}
|
}
|
||||||
ServiceProvider = ser;
|
ServiceProvider = ser;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly BsnesCore _bsnesCore;
|
private readonly BsnesCore _bsnesCore;
|
||||||
|
|
||||||
public bool IsSGB => _bsnesCore.IsSGB;
|
public bool IsSGB => _bsnesCore.IsSGB;
|
||||||
|
|
||||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
public ControllerDefinition ControllerDefinition => _bsnesCore.ControllerDefinition;
|
public ControllerDefinition ControllerDefinition => _bsnesCore.ControllerDefinition;
|
||||||
|
@ -64,20 +66,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetSignal)
|
if (resetSignal)
|
||||||
{
|
{
|
||||||
_bsnesCore.Api.core.snes_reset();
|
_bsnesCore.Api.core.snes_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (powerSignal)
|
if (powerSignal)
|
||||||
{
|
{
|
||||||
_bsnesCore.Api.core.snes_power();
|
_bsnesCore.Api.core.snes_power();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// run the core for one (sub-)frame
|
// run the core for one (sub-)frame
|
||||||
bool subFrameRequested = controller.IsPressed("Subframe");
|
bool subFrameRequested = controller.IsPressed("Subframe");
|
||||||
framePassed = _bsnesCore.Api.core.snes_run(subFrameRequested);
|
framePassed = _bsnesCore.Api.core.snes_run(subFrameRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!framePassed) _bsnesCore.IsLagFrame = false;
|
if (!framePassed) _bsnesCore.IsLagFrame = false;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
{
|
||||||
|
public interface IBSNESForGfxDebugger : ISpecializedEmulatorService
|
||||||
|
{
|
||||||
|
public interface SettingsObj
|
||||||
|
{
|
||||||
|
bool ShowBG1_0 { get; set; }
|
||||||
|
|
||||||
|
bool ShowBG1_1 { get; set; }
|
||||||
|
|
||||||
|
bool ShowBG2_0 { get; set; }
|
||||||
|
|
||||||
|
bool ShowBG2_1 { get; set; }
|
||||||
|
|
||||||
|
bool ShowBG3_0 { get; set; }
|
||||||
|
|
||||||
|
bool ShowBG3_1 { get; set; }
|
||||||
|
|
||||||
|
bool ShowBG4_0 { get; set; }
|
||||||
|
|
||||||
|
bool ShowBG4_1 { get; set; }
|
||||||
|
|
||||||
|
bool ShowOBJ_0 { get; set; }
|
||||||
|
|
||||||
|
bool ShowOBJ_1 { get; set; }
|
||||||
|
|
||||||
|
bool ShowOBJ_2 { get; set; }
|
||||||
|
|
||||||
|
bool ShowOBJ_3 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
SnesColors.ColorType CurrPalette { get; }
|
||||||
|
|
||||||
|
ScanlineHookManager? ScanlineHookManager { get; }
|
||||||
|
|
||||||
|
ISNESGraphicsDecoder CreateGraphicsDecoder();
|
||||||
|
|
||||||
|
SettingsObj GetSettings();
|
||||||
|
|
||||||
|
void PutSettings(SettingsObj s);
|
||||||
|
|
||||||
|
void SetPalette(SnesColors.ColorType palette);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
return _settings.Clone();
|
return _settings.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IBSNESForGfxDebugger.SettingsObj IBSNESForGfxDebugger.GetSettings()
|
||||||
|
=> GetSettings();
|
||||||
|
|
||||||
public SnesSyncSettings GetSyncSettings()
|
public SnesSyncSettings GetSyncSettings()
|
||||||
{
|
{
|
||||||
return _syncSettings.Clone();
|
return _syncSettings.Clone();
|
||||||
|
@ -26,6 +29,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
return PutSettingsDirtyBits.None;
|
return PutSettingsDirtyBits.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IBSNESForGfxDebugger.PutSettings(IBSNESForGfxDebugger.SettingsObj s)
|
||||||
|
=> PutSettings((SnesSettings) s);
|
||||||
|
|
||||||
public PutSettingsDirtyBits PutSyncSettings(SnesSyncSettings o)
|
public PutSettingsDirtyBits PutSyncSettings(SnesSyncSettings o)
|
||||||
{
|
{
|
||||||
bool ret = o.LeftPort != _syncSettings.LeftPort
|
bool ret = o.LeftPort != _syncSettings.LeftPort
|
||||||
|
@ -40,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
private SnesSettings _settings;
|
private SnesSettings _settings;
|
||||||
private SnesSyncSettings _syncSettings;
|
private SnesSyncSettings _syncSettings;
|
||||||
|
|
||||||
public class SnesSettings
|
public class SnesSettings : IBSNESForGfxDebugger.SettingsObj
|
||||||
{
|
{
|
||||||
public bool ShowBG1_0 { get; set; } = true;
|
public bool ShowBG1_0 { get; set; } = true;
|
||||||
public bool ShowBG2_0 { get; set; } = true;
|
public bool ShowBG2_0 { get; set; } = true;
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
[PortedCore(CoreNames.Bsnes, "byuu", "v87", "https://github.com/bsnes-emu/bsnes/tree/386ac87d21d14fafd15162d480a111209c9955ba")]
|
[PortedCore(CoreNames.Bsnes, "byuu", "v87", "https://github.com/bsnes-emu/bsnes/tree/386ac87d21d14fafd15162d480a111209c9955ba")]
|
||||||
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
|
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
|
||||||
public unsafe partial class LibsnesCore : IEmulator, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ICodeDataLogger,
|
public unsafe partial class LibsnesCore : IEmulator, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ICodeDataLogger,
|
||||||
IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>
|
IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>, IBSNESForGfxDebugger
|
||||||
{
|
{
|
||||||
[CoreConstructor(VSystemID.Raw.SGB)]
|
[CoreConstructor(VSystemID.Raw.SGB)]
|
||||||
[CoreConstructor(VSystemID.Raw.SNES)]
|
[CoreConstructor(VSystemID.Raw.SNES)]
|
||||||
|
@ -235,7 +235,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
public SnesColors.ColorType CurrPalette { get; private set; }
|
public SnesColors.ColorType CurrPalette { get; private set; }
|
||||||
|
|
||||||
public MyScanlineHookManager ScanlineHookManager { get; }
|
public void SetPalette(SnesColors.ColorType palette)
|
||||||
|
{
|
||||||
|
var s = GetSettings();
|
||||||
|
s.Palette = Enum.GetName(typeof(SnesColors.ColorType), palette);
|
||||||
|
PutSettings(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISNESGraphicsDecoder CreateGraphicsDecoder()
|
||||||
|
=> new SNESGraphicsDecoder(Api, CurrPalette);
|
||||||
|
|
||||||
|
public ScanlineHookManager ScanlineHookManager { get; }
|
||||||
|
|
||||||
public class MyScanlineHookManager : ScanlineHookManager
|
public class MyScanlineHookManager : ScanlineHookManager
|
||||||
{
|
{
|
||||||
|
@ -364,14 +374,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetPalette(SnesColors.ColorType pal)
|
|
||||||
{
|
|
||||||
CurrPalette = pal;
|
|
||||||
int[] tmp = SnesColors.GetLUT(pal);
|
|
||||||
fixed (int* p = &tmp[0])
|
|
||||||
Api.QUERY_set_color_lut((IntPtr)p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReadHook(uint addr)
|
private void ReadHook(uint addr)
|
||||||
{
|
{
|
||||||
if (MemoryCallbacks.HasReads)
|
if (MemoryCallbacks.HasReads)
|
||||||
|
@ -633,7 +635,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
private void RefreshPalette()
|
private void RefreshPalette()
|
||||||
{
|
{
|
||||||
SetPalette((SnesColors.ColorType)Enum.Parse(typeof(SnesColors.ColorType), _settings.Palette, false));
|
CurrPalette = (SnesColors.ColorType)Enum.Parse(typeof(SnesColors.ColorType), _settings.Palette, false);
|
||||||
|
int[] tmp = SnesColors.GetLUT(CurrPalette);
|
||||||
|
fixed (int* p = &tmp[0])
|
||||||
|
Api.QUERY_set_color_lut((IntPtr)p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,100 @@
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
{
|
{
|
||||||
public unsafe class SNESGraphicsDecoder : IDisposable, IMonitor
|
public unsafe interface ISNESGraphicsDecoder : IMonitor
|
||||||
|
{
|
||||||
|
public interface OAMInfo
|
||||||
|
{
|
||||||
|
ushort X { get; }
|
||||||
|
|
||||||
|
byte Y { get; }
|
||||||
|
|
||||||
|
int Tile { get; }
|
||||||
|
|
||||||
|
bool Table { get; }
|
||||||
|
|
||||||
|
int Palette { get; }
|
||||||
|
|
||||||
|
byte Priority { get; }
|
||||||
|
|
||||||
|
bool VFlip { get; }
|
||||||
|
|
||||||
|
bool HFlip { get; }
|
||||||
|
|
||||||
|
bool Size { get; }
|
||||||
|
|
||||||
|
int Address { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void CacheTiles();
|
||||||
|
|
||||||
|
int Colorize(int rgb555);
|
||||||
|
|
||||||
|
void Colorize(int* buf, int offset, int numpixels);
|
||||||
|
|
||||||
|
OAMInfo CreateOAMInfo(SNESGraphicsDecoder.ScreenInfo si, int num);
|
||||||
|
|
||||||
|
void DecodeBG(
|
||||||
|
int* screen,
|
||||||
|
int stride,
|
||||||
|
SNESGraphicsDecoder.TileEntry[] map,
|
||||||
|
int tiledataBaseAddr,
|
||||||
|
SNESGraphicsDecoder.ScreenSize size,
|
||||||
|
int bpp,
|
||||||
|
int tilesize,
|
||||||
|
int paletteStart);
|
||||||
|
|
||||||
|
void DecodeMode7BG(int* screen, int stride, bool extBg);
|
||||||
|
|
||||||
|
void DirectColorify(int* screen, int numPixels);
|
||||||
|
|
||||||
|
SNESGraphicsDecoder.TileEntry[] FetchMode7Tilemap();
|
||||||
|
|
||||||
|
SNESGraphicsDecoder.TileEntry[] FetchTilemap(int addr, SNESGraphicsDecoder.ScreenSize size);
|
||||||
|
|
||||||
|
int[] GetPalette();
|
||||||
|
|
||||||
|
void Paletteize(int* buf, int offset, int startcolor, int numpixels);
|
||||||
|
|
||||||
|
void RenderMode7TilesToScreen(
|
||||||
|
int* screen,
|
||||||
|
int stride,
|
||||||
|
bool ext,
|
||||||
|
bool directColor,
|
||||||
|
int tilesWide = 16,
|
||||||
|
int startTile = 0,
|
||||||
|
int numTiles = 256);
|
||||||
|
|
||||||
|
void RenderSpriteToScreen(
|
||||||
|
int* screen,
|
||||||
|
int stride,
|
||||||
|
int destx,
|
||||||
|
int desty,
|
||||||
|
SNESGraphicsDecoder.ScreenInfo si,
|
||||||
|
int spritenum,
|
||||||
|
OAMInfo oam = null,
|
||||||
|
int xlimit = 1024,
|
||||||
|
int ylimit = 1024,
|
||||||
|
byte[,] spriteMap = null);
|
||||||
|
|
||||||
|
void RenderTilesToScreen(
|
||||||
|
int* screen,
|
||||||
|
int stride,
|
||||||
|
int bpp,
|
||||||
|
int startcolor,
|
||||||
|
int startTile = 0,
|
||||||
|
int numTiles = -1);
|
||||||
|
|
||||||
|
SNESGraphicsDecoder.ScreenInfo ScanScreenInfo();
|
||||||
|
|
||||||
|
void SetBackColor(int snescol = -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe class SNESGraphicsDecoder : ISNESGraphicsDecoder
|
||||||
{
|
{
|
||||||
public class PaletteSelection
|
public class PaletteSelection
|
||||||
{
|
{
|
||||||
|
@ -48,16 +138,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dimensions[,] ObjSizes =
|
public static Size[,] ObjSizes =
|
||||||
{
|
{
|
||||||
{ new Dimensions(8,8), new Dimensions(16,16) },
|
{ new(8,8), new(16,16) },
|
||||||
{ new Dimensions(8,8), new Dimensions(32,32) },
|
{ new(8,8), new(32,32) },
|
||||||
{ new Dimensions(8,8), new Dimensions(64,64) },
|
{ new(8,8), new(64,64) },
|
||||||
{ new Dimensions(16,16), new Dimensions(32,32) },
|
{ new(16,16), new(32,32) },
|
||||||
{ new Dimensions(16,16), new Dimensions(64,64) },
|
{ new(16,16), new(64,64) },
|
||||||
{ new Dimensions(32,32), new Dimensions(64,64) },
|
{ new(32,32), new(64,64) },
|
||||||
{ new Dimensions(16,32), new Dimensions(32,64) },
|
{ new(16,32), new(32,64) },
|
||||||
{ new Dimensions(16,32), new Dimensions(32,32) }
|
{ new(16,32), new(32,32) }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Dimensions SizeInBlocksForBGSize(ScreenSize size)
|
public static Dimensions SizeInBlocksForBGSize(ScreenSize size)
|
||||||
|
@ -199,27 +289,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
public BGInfo this[int index] => bgs[index - 1];
|
public BGInfo this[int index] => bgs[index - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ModeInfo
|
public class OAMInfo : ISNESGraphicsDecoder.OAMInfo
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// the mode number, i.e. Mode 7
|
|
||||||
/// </summary>
|
|
||||||
public int MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OAMInfo
|
|
||||||
{
|
{
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
public int X { get; }
|
public ushort X { get; }
|
||||||
public int Y { get; }
|
public byte Y { get; }
|
||||||
public int Tile { get; }
|
public int Tile { get; }
|
||||||
public int Name { get; }
|
public bool Table { get; }
|
||||||
public int Table { get; }
|
|
||||||
public int Palette { get; }
|
public int Palette { get; }
|
||||||
public int Priority { get; }
|
public byte Priority { get; }
|
||||||
public bool VFlip { get; }
|
public bool VFlip { get; }
|
||||||
public bool HFlip { get; }
|
public bool HFlip { get; }
|
||||||
public int Size { get; }
|
public bool Size { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// tiledata address
|
/// tiledata address
|
||||||
|
@ -229,15 +310,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
public OAMInfo(SNESGraphicsDecoder dec, ScreenInfo si, int num)
|
public OAMInfo(SNESGraphicsDecoder dec, ScreenInfo si, int num)
|
||||||
{
|
{
|
||||||
Index = num;
|
Index = num;
|
||||||
|
|
||||||
int lowaddr = num*4;
|
int lowaddr = num*4;
|
||||||
X = dec.oam[lowaddr++];
|
X = dec.oam[lowaddr++];
|
||||||
Y = dec.oam[lowaddr++];
|
Y = dec.oam[lowaddr++];
|
||||||
Name = dec.oam[lowaddr++];
|
byte name = dec.oam[lowaddr++];
|
||||||
Table = dec.oam[lowaddr] & 1;
|
Table = (dec.oam[lowaddr] & 1) == 1;
|
||||||
Palette = (dec.oam[lowaddr]>>1) & 7;
|
Palette = (dec.oam[lowaddr]>>1) & 7;
|
||||||
Priority = (dec.oam[lowaddr] >> 4) & 3;
|
Priority = (byte)((dec.oam[lowaddr] >> 4) & 3);
|
||||||
HFlip = ((dec.oam[lowaddr] >> 6) & 1)==1;
|
HFlip = ((dec.oam[lowaddr] >> 6) & 1) == 1;
|
||||||
VFlip = ((dec.oam[lowaddr] >> 7) & 1) == 1;
|
VFlip = ((dec.oam[lowaddr] >> 7) & 1) == 1;
|
||||||
|
|
||||||
int highaddr = num / 4;
|
int highaddr = num / 4;
|
||||||
|
@ -246,13 +327,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
high >>= shift;
|
high >>= shift;
|
||||||
int x = high & 1;
|
int x = high & 1;
|
||||||
high >>= 1;
|
high >>= 1;
|
||||||
Size = high & 1;
|
Size = (high & 1) != 0;
|
||||||
X |= (x << 8);
|
X = (ushort)(X | (x << 8));
|
||||||
X = (X << 23) >> 23;
|
|
||||||
|
|
||||||
Tile = Table*256 + Name;
|
Tile = name + (Table ? 256 : 0);
|
||||||
Address = 32 * Tile;
|
Address = 32 * Tile;
|
||||||
|
|
||||||
if (Tile < 256)
|
if (Tile < 256)
|
||||||
Address += si.OBJTable0Addr;
|
Address += si.OBJTable0Addr;
|
||||||
else
|
else
|
||||||
|
@ -264,240 +344,53 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
public class ScreenInfo
|
public class ScreenInfo
|
||||||
{
|
{
|
||||||
public Dimensions ObjSizeBounds;
|
public Size ObjSizeBounds;
|
||||||
public Dimensions ObjSizeBoundsSquare;
|
public Size ObjSizeBoundsSquare;
|
||||||
|
|
||||||
public BGInfos BG = new BGInfos();
|
public BGInfos BG = new BGInfos();
|
||||||
|
|
||||||
public ModeInfo Mode = new ModeInfo();
|
public int Mode { get; init; }
|
||||||
|
public bool Mode1_BG3_Priority { get; init; }
|
||||||
|
|
||||||
public bool Mode1_BG3_Priority { get; private set; }
|
public bool SETINI_Mode7ExtBG { get; init; }
|
||||||
|
public bool SETINI_HiRes { get; init; }
|
||||||
|
public bool SETINI_Overscan { get; init; }
|
||||||
|
public bool SETINI_ObjInterlace { get; init; }
|
||||||
|
public bool SETINI_ScreenInterlace { get; init; }
|
||||||
|
|
||||||
public bool SETINI_Mode7ExtBG { get; private set; }
|
public int CGWSEL_ColorMask { get; init; }
|
||||||
public bool SETINI_HiRes { get; private set; }
|
public int CGWSEL_ColorSubMask { get; init; }
|
||||||
public bool SETINI_Overscan { get; private set; }
|
public int CGWSEL_AddSubMode { get; init; }
|
||||||
public bool SETINI_ObjInterlace { get; private set; }
|
public bool CGWSEL_DirectColor { get; init; }
|
||||||
public bool SETINI_ScreenInterlace { get; private set; }
|
public int CGADSUB_AddSub { get; init; }
|
||||||
|
public bool CGADSUB_Half { get; init; }
|
||||||
|
|
||||||
public int CGWSEL_ColorMask { get; private set; }
|
public int OBSEL_Size { get; init; }
|
||||||
public int CGWSEL_ColorSubMask { get; private set; }
|
public int OBSEL_NameSel { get; init; }
|
||||||
public int CGWSEL_AddSubMode { get; private set; }
|
public int OBSEL_NameBase { get; init; }
|
||||||
public bool CGWSEL_DirectColor { get; private set; }
|
|
||||||
public int CGADSUB_AddSub { get; private set; }
|
|
||||||
public bool CGADSUB_Half { get; private set; }
|
|
||||||
|
|
||||||
public int OBSEL_Size { get; private set; }
|
public int OBJTable0Addr { get; init; }
|
||||||
public int OBSEL_NameSel { get; private set; }
|
public int OBJTable1Addr { get; init; }
|
||||||
public int OBSEL_NameBase { get; private set; }
|
|
||||||
|
|
||||||
public int OBJTable0Addr { get; private set; }
|
public bool OBJ_MainEnabled { get; init; }
|
||||||
public int OBJTable1Addr { get; private set; }
|
public bool OBJ_SubEnabled { get; init; }
|
||||||
|
public bool OBJ_MathEnabled { get; init; }
|
||||||
|
public bool BK_MathEnabled { get; init; }
|
||||||
|
|
||||||
public bool OBJ_MainEnabled { get; private set; }
|
public int M7HOFS { get; init; }
|
||||||
public bool OBJ_SubEnabled { get; private set; }
|
public int M7VOFS { get; init; }
|
||||||
public bool OBJ_MathEnabled { get; private set; }
|
public int M7A { get; init; }
|
||||||
public bool BK_MathEnabled { get; private set; }
|
public int M7B { get; init; }
|
||||||
|
public int M7C { get; init; }
|
||||||
public int M7HOFS { get; private set; }
|
public int M7D { get; init; }
|
||||||
public int M7VOFS { get; private set; }
|
public int M7X { get; init; }
|
||||||
public int M7A { get; private set; }
|
public int M7Y { get; init; }
|
||||||
public int M7B { get; private set; }
|
public int M7SEL_REPEAT { get; init; }
|
||||||
public int M7C { get; private set; }
|
public bool M7SEL_HFLIP { get; init; }
|
||||||
public int M7D { get; private set; }
|
public bool M7SEL_VFLIP { get; init; }
|
||||||
public int M7X { get; private set; }
|
|
||||||
public int M7Y { get; private set; }
|
|
||||||
public int M7SEL_REPEAT { get; private set; }
|
|
||||||
public bool M7SEL_HFLIP { get; private set; }
|
|
||||||
public bool M7SEL_VFLIP { get; private set; }
|
|
||||||
|
|
||||||
public static ScreenInfo GetScreenInfo(LibsnesApi api)
|
|
||||||
{
|
|
||||||
var si = new ScreenInfo();
|
|
||||||
|
|
||||||
si.Mode1_BG3_Priority = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_PRIORITY) == 1;
|
|
||||||
|
|
||||||
si.OBSEL_Size = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_SIZE);
|
|
||||||
si.OBSEL_NameSel = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_NAMESEL);
|
|
||||||
si.OBSEL_NameBase = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_NAMEBASE);
|
|
||||||
|
|
||||||
si.ObjSizeBounds = ObjSizes[si.OBSEL_Size,1];
|
|
||||||
int square = Math.Max(si.ObjSizeBounds.Width, si.ObjSizeBounds.Height);
|
|
||||||
si.ObjSizeBoundsSquare = new Dimensions(square, square);
|
|
||||||
|
|
||||||
|
|
||||||
si.OBJTable0Addr = si.OBSEL_NameBase << 14;
|
|
||||||
si.OBJTable1Addr = (si.OBJTable0Addr + ((si.OBSEL_NameSel + 1) << 13)) & 0xFFFF;
|
|
||||||
|
|
||||||
si.SETINI_Mode7ExtBG = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_MODE7_EXTBG) == 1;
|
|
||||||
si.SETINI_HiRes = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_HIRES) == 1;
|
|
||||||
si.SETINI_Overscan = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_OVERSCAN) == 1;
|
|
||||||
si.SETINI_ObjInterlace = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_OBJ_INTERLACE) == 1;
|
|
||||||
si.SETINI_ScreenInterlace = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_SCREEN_INTERLACE) == 1;
|
|
||||||
|
|
||||||
si.CGWSEL_ColorMask = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_COLORMASK);
|
|
||||||
si.CGWSEL_ColorSubMask = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_COLORSUBMASK);
|
|
||||||
si.CGWSEL_AddSubMode = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_ADDSUBMODE);
|
|
||||||
si.CGWSEL_DirectColor = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_DIRECTCOLOR) == 1;
|
|
||||||
|
|
||||||
si.CGADSUB_AddSub = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_MODE);
|
|
||||||
si.CGADSUB_Half = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_HALF) == 1;
|
|
||||||
|
|
||||||
si.OBJ_MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_OBJ) == 1;
|
|
||||||
si.OBJ_SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_OBJ) == 1;
|
|
||||||
si.OBJ_MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_OBJ) == 1;
|
|
||||||
si.BK_MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BACKDROP) == 1;
|
|
||||||
|
|
||||||
si.Mode.MODE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG_MODE);
|
|
||||||
si.BG.BG1.Bpp = ModeBpps[si.Mode.MODE, 0];
|
|
||||||
si.BG.BG2.Bpp = ModeBpps[si.Mode.MODE, 1];
|
|
||||||
si.BG.BG3.Bpp = ModeBpps[si.Mode.MODE, 2];
|
|
||||||
si.BG.BG4.Bpp = ModeBpps[si.Mode.MODE, 3];
|
|
||||||
|
|
||||||
//initial setting of mode type (derived from bpp table.. mode7 bg types will be fixed up later)
|
|
||||||
for(int i=1;i<=4;i++)
|
|
||||||
si.BG[i].BGMode = si.BG[i].Bpp == 0 ? BGMode.Unavailable : BGMode.Text;
|
|
||||||
|
|
||||||
si.BG.BG1.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_TILESIZE);
|
|
||||||
si.BG.BG2.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_TILESIZE);
|
|
||||||
si.BG.BG3.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_TILESIZE);
|
|
||||||
si.BG.BG4.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_TILESIZE);
|
|
||||||
|
|
||||||
si.BG.BG1.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_SCSIZE);
|
|
||||||
si.BG.BG2.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_SCSIZE);
|
|
||||||
si.BG.BG3.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_SCSIZE);
|
|
||||||
si.BG.BG4.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_SCSIZE);
|
|
||||||
si.BG.BG1.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_SCADDR);
|
|
||||||
si.BG.BG2.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_SCADDR);
|
|
||||||
si.BG.BG3.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_SCADDR);
|
|
||||||
si.BG.BG4.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_SCADDR);
|
|
||||||
si.BG.BG1.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_TDADDR);
|
|
||||||
si.BG.BG2.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_TDADDR);
|
|
||||||
si.BG.BG3.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_TDADDR);
|
|
||||||
si.BG.BG4.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_TDADDR);
|
|
||||||
|
|
||||||
si.BG.BG1.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG1) == 1;
|
|
||||||
si.BG.BG2.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG2) == 1;
|
|
||||||
si.BG.BG3.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG3) == 1;
|
|
||||||
si.BG.BG4.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG4) == 1;
|
|
||||||
si.BG.BG1.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG1) == 1;
|
|
||||||
si.BG.BG2.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG2) == 1;
|
|
||||||
si.BG.BG3.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG3) == 1;
|
|
||||||
si.BG.BG4.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG4) == 1;
|
|
||||||
si.BG.BG1.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG1) == 1;
|
|
||||||
si.BG.BG2.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG2) == 1;
|
|
||||||
si.BG.BG3.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG3) == 1;
|
|
||||||
si.BG.BG4.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG4) == 1;
|
|
||||||
|
|
||||||
si.BG.BG1.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1HOFS);
|
|
||||||
si.BG.BG1.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1VOFS);
|
|
||||||
si.BG.BG2.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2HOFS);
|
|
||||||
si.BG.BG2.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2VOFS);
|
|
||||||
si.BG.BG3.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3HOFS);
|
|
||||||
si.BG.BG3.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3VOFS);
|
|
||||||
si.BG.BG4.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4HOFS);
|
|
||||||
si.BG.BG4.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4VOFS);
|
|
||||||
|
|
||||||
si.M7HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7HOFS);
|
|
||||||
si.M7VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7VOFS);
|
|
||||||
si.M7A = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7A);
|
|
||||||
si.M7B = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7B);
|
|
||||||
si.M7C = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7C);
|
|
||||||
si.M7D = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7D);
|
|
||||||
si.M7X = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7X);
|
|
||||||
si.M7Y = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7Y);
|
|
||||||
si.M7Y = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7Y);
|
|
||||||
si.M7SEL_REPEAT = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_REPEAT);
|
|
||||||
si.M7SEL_HFLIP = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_HFLIP)!=0;
|
|
||||||
si.M7SEL_VFLIP = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_VFLIP)!=0;
|
|
||||||
|
|
||||||
for (int i = 1; i <= 4; i++)
|
|
||||||
{
|
|
||||||
si.BG[i].Mode = si.Mode.MODE;
|
|
||||||
si.BG[i].TiledataAddr = si.BG[i].TDADDR << 13;
|
|
||||||
si.BG[i].ScreenAddr = si.BG[i].SCADDR << 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
//fixup irregular things for mode 7
|
|
||||||
if (si.Mode.MODE == 7)
|
|
||||||
{
|
|
||||||
si.BG.BG1.TiledataAddr = 0;
|
|
||||||
si.BG.BG1.ScreenAddr = 0;
|
|
||||||
|
|
||||||
if (si.CGWSEL_DirectColor)
|
|
||||||
{
|
|
||||||
si.BG.BG1.BGMode = BGMode.Mode7DC;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
si.BG.BG1.BGMode = BGMode.Mode7;
|
|
||||||
|
|
||||||
if (si.SETINI_Mode7ExtBG)
|
|
||||||
{
|
|
||||||
si.BG.BG2.BGMode = BGMode.Mode7Ext;
|
|
||||||
si.BG.BG2.Bpp = 7;
|
|
||||||
si.BG.BG2.TiledataAddr = 0;
|
|
||||||
si.BG.BG2.ScreenAddr = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//determine which colors each BG could use
|
|
||||||
switch (si.Mode.MODE)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 32);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(32, 32);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(64, 32);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(96, 32);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 32);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
|
||||||
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
|
||||||
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return si;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly int[,] ModeBpps = {
|
public static readonly int[,] ModeBpps = {
|
||||||
{2,2,2,2},
|
{2,2,2,2},
|
||||||
{4,4,2,0},
|
{4,4,2,0},
|
||||||
{4,4,0,0},
|
{4,4,0,0},
|
||||||
|
@ -512,7 +405,182 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
public ScreenInfo ScanScreenInfo()
|
public ScreenInfo ScanScreenInfo()
|
||||||
{
|
{
|
||||||
return ScreenInfo.GetScreenInfo(api);
|
int OBSEL_NameSel = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_NAMESEL);
|
||||||
|
int OBSEL_NameBase = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_NAMEBASE);
|
||||||
|
|
||||||
|
var si = new ScreenInfo
|
||||||
|
{
|
||||||
|
Mode = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG_MODE),
|
||||||
|
Mode1_BG3_Priority = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_PRIORITY) == 1,
|
||||||
|
OBSEL_Size = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.OBSEL_SIZE),
|
||||||
|
OBSEL_NameSel = OBSEL_NameSel,
|
||||||
|
OBSEL_NameBase = OBSEL_NameBase,
|
||||||
|
OBJTable0Addr = OBSEL_NameBase << 14,
|
||||||
|
OBJTable1Addr = ((OBSEL_NameBase << 14) + ((OBSEL_NameSel + 1) << 13)) & 0xFFFF,
|
||||||
|
SETINI_Mode7ExtBG = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_MODE7_EXTBG) == 1,
|
||||||
|
SETINI_HiRes = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_HIRES) == 1,
|
||||||
|
SETINI_Overscan = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_OVERSCAN) == 1,
|
||||||
|
SETINI_ObjInterlace = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_OBJ_INTERLACE) == 1,
|
||||||
|
SETINI_ScreenInterlace = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.SETINI_SCREEN_INTERLACE) == 1,
|
||||||
|
CGWSEL_ColorMask = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_COLORMASK),
|
||||||
|
CGWSEL_ColorSubMask = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_COLORSUBMASK),
|
||||||
|
CGWSEL_AddSubMode = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_ADDSUBMODE),
|
||||||
|
CGWSEL_DirectColor = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGWSEL_DIRECTCOLOR) == 1,
|
||||||
|
CGADSUB_AddSub = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_MODE),
|
||||||
|
CGADSUB_Half = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_HALF) == 1,
|
||||||
|
OBJ_MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_OBJ) == 1,
|
||||||
|
OBJ_SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_OBJ) == 1,
|
||||||
|
OBJ_MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_OBJ) == 1,
|
||||||
|
BK_MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BACKDROP) == 1,
|
||||||
|
M7HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7HOFS),
|
||||||
|
M7VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7VOFS),
|
||||||
|
M7A = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7A),
|
||||||
|
M7B = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7B),
|
||||||
|
M7C = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7C),
|
||||||
|
M7D = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7D),
|
||||||
|
M7X = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7X),
|
||||||
|
M7Y = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7Y),
|
||||||
|
M7SEL_REPEAT = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_REPEAT),
|
||||||
|
M7SEL_HFLIP = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_HFLIP)!=0,
|
||||||
|
M7SEL_VFLIP = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.M7SEL_VFLIP)!=0,
|
||||||
|
};
|
||||||
|
|
||||||
|
si.ObjSizeBounds = ObjSizes[si.OBSEL_Size,1];
|
||||||
|
int square = Math.Max(si.ObjSizeBounds.Width, si.ObjSizeBounds.Height);
|
||||||
|
si.ObjSizeBoundsSquare = new Size(square, square);
|
||||||
|
|
||||||
|
si.BG.BG1.Bpp = ModeBpps[si.Mode, 0];
|
||||||
|
si.BG.BG2.Bpp = ModeBpps[si.Mode, 1];
|
||||||
|
si.BG.BG3.Bpp = ModeBpps[si.Mode, 2];
|
||||||
|
si.BG.BG4.Bpp = ModeBpps[si.Mode, 3];
|
||||||
|
|
||||||
|
//initial setting of mode type (derived from bpp table.. mode7 bg types will be fixed up later)
|
||||||
|
for(int i=1;i<=4;i++)
|
||||||
|
si.BG[i].BGMode = si.BG[i].Bpp == 0 ? BGMode.Unavailable : BGMode.Text;
|
||||||
|
|
||||||
|
si.BG.BG1.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_TILESIZE);
|
||||||
|
si.BG.BG2.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_TILESIZE);
|
||||||
|
si.BG.BG3.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_TILESIZE);
|
||||||
|
si.BG.BG4.TILESIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_TILESIZE);
|
||||||
|
|
||||||
|
si.BG.BG1.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_SCSIZE);
|
||||||
|
si.BG.BG2.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_SCSIZE);
|
||||||
|
si.BG.BG3.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_SCSIZE);
|
||||||
|
si.BG.BG4.SCSIZE = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_SCSIZE);
|
||||||
|
si.BG.BG1.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_SCADDR);
|
||||||
|
si.BG.BG2.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_SCADDR);
|
||||||
|
si.BG.BG3.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_SCADDR);
|
||||||
|
si.BG.BG4.SCADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_SCADDR);
|
||||||
|
si.BG.BG1.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1_TDADDR);
|
||||||
|
si.BG.BG2.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2_TDADDR);
|
||||||
|
si.BG.BG3.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3_TDADDR);
|
||||||
|
si.BG.BG4.TDADDR = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4_TDADDR);
|
||||||
|
|
||||||
|
si.BG.BG1.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG1) == 1;
|
||||||
|
si.BG.BG2.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG2) == 1;
|
||||||
|
si.BG.BG3.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG3) == 1;
|
||||||
|
si.BG.BG4.MainEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TM_BG4) == 1;
|
||||||
|
si.BG.BG1.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG1) == 1;
|
||||||
|
si.BG.BG2.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG2) == 1;
|
||||||
|
si.BG.BG3.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG3) == 1;
|
||||||
|
si.BG.BG4.SubEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.TS_BG4) == 1;
|
||||||
|
si.BG.BG1.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG1) == 1;
|
||||||
|
si.BG.BG2.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG2) == 1;
|
||||||
|
si.BG.BG3.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG3) == 1;
|
||||||
|
si.BG.BG4.MathEnabled = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.CGADSUB_BG4) == 1;
|
||||||
|
|
||||||
|
si.BG.BG1.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1HOFS);
|
||||||
|
si.BG.BG1.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG1VOFS);
|
||||||
|
si.BG.BG2.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2HOFS);
|
||||||
|
si.BG.BG2.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG2VOFS);
|
||||||
|
si.BG.BG3.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3HOFS);
|
||||||
|
si.BG.BG3.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG3VOFS);
|
||||||
|
si.BG.BG4.HOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4HOFS);
|
||||||
|
si.BG.BG4.VOFS = api.QUERY_peek_logical_register(LibsnesApi.SNES_REG.BG4VOFS);
|
||||||
|
|
||||||
|
for (int i = 1; i <= 4; i++)
|
||||||
|
{
|
||||||
|
si.BG[i].Mode = si.Mode;
|
||||||
|
si.BG[i].TiledataAddr = si.BG[i].TDADDR << 13;
|
||||||
|
si.BG[i].ScreenAddr = si.BG[i].SCADDR << 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fixup irregular things for mode 7
|
||||||
|
if (si.Mode == 7)
|
||||||
|
{
|
||||||
|
si.BG.BG1.TiledataAddr = 0;
|
||||||
|
si.BG.BG1.ScreenAddr = 0;
|
||||||
|
|
||||||
|
if (si.CGWSEL_DirectColor)
|
||||||
|
{
|
||||||
|
si.BG.BG1.BGMode = BGMode.Mode7DC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
si.BG.BG1.BGMode = BGMode.Mode7;
|
||||||
|
|
||||||
|
if (si.SETINI_Mode7ExtBG)
|
||||||
|
{
|
||||||
|
si.BG.BG2.BGMode = BGMode.Mode7Ext;
|
||||||
|
si.BG.BG2.Bpp = 7;
|
||||||
|
si.BG.BG2.TiledataAddr = 0;
|
||||||
|
si.BG.BG2.ScreenAddr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//determine which colors each BG could use
|
||||||
|
switch (si.Mode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(32, 32);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(64, 32);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(96, 32);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 32);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
si.BG.BG1.PaletteSelection = new PaletteSelection(0, 256);
|
||||||
|
si.BG.BG2.PaletteSelection = new PaletteSelection(0, 128);
|
||||||
|
si.BG.BG3.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
si.BG.BG4.PaletteSelection = new PaletteSelection(0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
//the same basic color table that libsnes uses to convert from snes 555 to rgba32
|
//the same basic color table that libsnes uses to convert from snes 555 to rgba32
|
||||||
|
@ -565,11 +633,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
public int address;
|
public int address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
public enum TileEntryFlags : byte
|
public enum TileEntryFlags : byte
|
||||||
{
|
{
|
||||||
None = 0, Priority = 1, Horz = 2, Vert = 4,
|
None = 0, Priority = 1, Horz = 2, Vert = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ISNESGraphicsDecoder.OAMInfo CreateOAMInfo(ScreenInfo si, int num)
|
||||||
|
=> new OAMInfo(this, si, num);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// decodes a mode7 BG. youll still need to paletteize and colorize it.
|
/// decodes a mode7 BG. youll still need to paletteize and colorize it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -650,7 +722,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
{
|
{
|
||||||
int mapIndex = mty * dims.Width + mtx;
|
int mapIndex = mty * dims.Width + mtx;
|
||||||
var te = map[mapIndex];
|
var te = map[mapIndex];
|
||||||
|
|
||||||
//apply metatile flipping
|
//apply metatile flipping
|
||||||
int tnx = tx, tny = ty;
|
int tnx = tx, tny = ty;
|
||||||
if (tilesize == 16)
|
if (tilesize == 16)
|
||||||
|
@ -766,13 +838,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
private readonly int[][] _tileCache = new int[18][];
|
private readonly int[][] _tileCache = new int[18][];
|
||||||
|
|
||||||
private bool usingUserBackColor = false;
|
private bool usingUserBackColor;
|
||||||
private int userBackColor;
|
private int userBackColor;
|
||||||
|
|
||||||
public void SetBackColor(int snescol)
|
public void SetBackColor(int snescol)
|
||||||
{
|
{
|
||||||
usingUserBackColor = true;
|
if (snescol == -1)
|
||||||
userBackColor = snescol;
|
{
|
||||||
|
usingUserBackColor = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usingUserBackColor = true;
|
||||||
|
userBackColor = snescol;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -909,11 +988,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
/// we might need 16x16 unscrambling and some other perks here eventually.
|
/// we might need 16x16 unscrambling and some other perks here eventually.
|
||||||
/// provide a start color to use as the basis for the palette
|
/// provide a start color to use as the basis for the palette
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RenderTilesToScreen(int* screen, int tilesWide, int tilesTall, int stride, int bpp, int startcolor, int startTile = 0, int numTiles = -1, bool descramble16 = false)
|
public void RenderTilesToScreen(int* screen, int stride, int bpp, int startcolor, int startTile = 0, int numTiles = -1)
|
||||||
{
|
{
|
||||||
if (numTiles == -1)
|
if (numTiles == -1)
|
||||||
numTiles = 8192 / bpp;
|
numTiles = 8192 / bpp;
|
||||||
int[] tilebuf = _tileCache[bpp];
|
int[] tilebuf = _tileCache[bpp];
|
||||||
|
int tilesWide = stride / 8;
|
||||||
for (int i = 0; i < numTiles; i++)
|
for (int i = 0; i < numTiles; i++)
|
||||||
{
|
{
|
||||||
int tnum = startTile + i;
|
int tnum = startTile + i;
|
||||||
|
@ -935,20 +1015,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
public void RenderSpriteToScreen(int* screen, int stride, int destx, int desty, ScreenInfo si, int spritenum, ISNESGraphicsDecoder.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] };
|
oam ??= new OAMInfo(this, si, spritenum);
|
||||||
if(oam == null)
|
var dim = ObjSizes[si.OBSEL_Size, oam.Size ? 1 : 0];
|
||||||
oam = new OAMInfo(this, si, spritenum);
|
|
||||||
var dim = dims[oam.Size];
|
|
||||||
|
|
||||||
int[] tilebuf = _tileCache[4];
|
int[] tilebuf = _tileCache[4];
|
||||||
|
|
||||||
int baseaddr;
|
int baseaddr = oam.Table ? si.OBJTable1Addr : si.OBJTable0Addr;
|
||||||
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
|
//TODO - flips of 'undocumented' rectangular oam settings are wrong. probably easy to do right, but we need a test
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,7 @@ using namespace SuperFamicom;
|
||||||
|
|
||||||
|
|
||||||
//zero 05-sep-2012
|
//zero 05-sep-2012
|
||||||
// currently unused; was only used in the graphics debugger as far as i can see
|
EXPORT int snes_peek_logical_register(SNES_REGISTER reg)
|
||||||
int snes_peek_logical_register(int reg)
|
|
||||||
{
|
{
|
||||||
if (SuperFamicom::system.fastPPU())
|
if (SuperFamicom::system.fastPPU())
|
||||||
switch(reg)
|
switch(reg)
|
||||||
|
@ -21,88 +20,88 @@ int snes_peek_logical_register(int reg)
|
||||||
// 3-may-2021 above timestamp left for reference because i like it
|
// 3-may-2021 above timestamp left for reference because i like it
|
||||||
|
|
||||||
//$2105
|
//$2105
|
||||||
case SNES_REG_BG_MODE: return ppufast.io.bgMode;
|
case BG_MODE: return ppufast.io.bgMode;
|
||||||
case SNES_REG_BG3_PRIORITY: return ppufast.io.bgPriority;
|
case BG3_PRIORITY: return ppufast.io.bgPriority;
|
||||||
case SNES_REG_BG1_TILESIZE: return ppufast.io.bg1.tileSize;
|
case BG1_TILESIZE: return ppufast.io.bg1.tileSize;
|
||||||
case SNES_REG_BG2_TILESIZE: return ppufast.io.bg2.tileSize;
|
case BG2_TILESIZE: return ppufast.io.bg2.tileSize;
|
||||||
case SNES_REG_BG3_TILESIZE: return ppufast.io.bg3.tileSize;
|
case BG3_TILESIZE: return ppufast.io.bg3.tileSize;
|
||||||
case SNES_REG_BG4_TILESIZE: return ppufast.io.bg4.tileSize;
|
case BG4_TILESIZE: return ppufast.io.bg4.tileSize;
|
||||||
//$2107
|
//$2107
|
||||||
case SNES_REG_BG1_SCADDR: return ppufast.io.bg1.screenAddress >> 8;
|
case BG1_SCADDR: return ppufast.io.bg1.screenAddress >> 8;
|
||||||
case SNES_REG_BG1_SCSIZE: return ppufast.io.bg1.screenSize;
|
case BG1_SCSIZE: return ppufast.io.bg1.screenSize;
|
||||||
//$2108
|
//$2108
|
||||||
case SNES_REG_BG2_SCADDR: return ppufast.io.bg2.screenAddress >> 8;
|
case BG2_SCADDR: return ppufast.io.bg2.screenAddress >> 8;
|
||||||
case SNES_REG_BG2_SCSIZE: return ppufast.io.bg2.screenSize;
|
case BG2_SCSIZE: return ppufast.io.bg2.screenSize;
|
||||||
//$2109
|
//$2109
|
||||||
case SNES_REG_BG3_SCADDR: return ppufast.io.bg3.screenAddress >> 8;
|
case BG3_SCADDR: return ppufast.io.bg3.screenAddress >> 8;
|
||||||
case SNES_REG_BG3_SCSIZE: return ppufast.io.bg3.screenSize;
|
case BG3_SCSIZE: return ppufast.io.bg3.screenSize;
|
||||||
//$210A
|
//$210A
|
||||||
case SNES_REG_BG4_SCADDR: return ppufast.io.bg4.screenAddress >> 8;
|
case BG4_SCADDR: return ppufast.io.bg4.screenAddress >> 8;
|
||||||
case SNES_REG_BG4_SCSIZE: return ppufast.io.bg4.screenSize;
|
case BG4_SCSIZE: return ppufast.io.bg4.screenSize;
|
||||||
//$210B
|
//$210B
|
||||||
case SNES_REG_BG1_TDADDR: return ppufast.io.bg1.tiledataAddress >> 12;
|
case BG1_TDADDR: return ppufast.io.bg1.tiledataAddress >> 12;
|
||||||
case SNES_REG_BG2_TDADDR: return ppufast.io.bg2.tiledataAddress >> 12;
|
case BG2_TDADDR: return ppufast.io.bg2.tiledataAddress >> 12;
|
||||||
//$210C
|
//$210C
|
||||||
case SNES_REG_BG3_TDADDR: return ppufast.io.bg3.tiledataAddress >> 12;
|
case BG3_TDADDR: return ppufast.io.bg3.tiledataAddress >> 12;
|
||||||
case SNES_REG_BG4_TDADDR: return ppufast.io.bg4.tiledataAddress >> 12;
|
case BG4_TDADDR: return ppufast.io.bg4.tiledataAddress >> 12;
|
||||||
//$2133 SETINI
|
//$2133 SETINI
|
||||||
case SNES_REG_SETINI_MODE7_EXTBG: return ppufast.io.extbg;
|
case SETINI_MODE7_EXTBG: return ppufast.io.extbg;
|
||||||
case SNES_REG_SETINI_HIRES: return ppufast.io.pseudoHires;
|
case SETINI_HIRES: return ppufast.io.pseudoHires;
|
||||||
case SNES_REG_SETINI_OVERSCAN: return ppufast.io.overscan;
|
case SETINI_OVERSCAN: return ppufast.io.overscan;
|
||||||
case SNES_REG_SETINI_OBJ_INTERLACE: return ppufast.io.obj.interlace;
|
case SETINI_OBJ_INTERLACE: return ppufast.io.obj.interlace;
|
||||||
case SNES_REG_SETINI_SCREEN_INTERLACE: return ppufast.io.interlace;
|
case SETINI_SCREEN_INTERLACE: return ppufast.io.interlace;
|
||||||
//$2130 CGWSEL
|
//$2130 CGWSEL
|
||||||
case SNES_REG_CGWSEL_COLORMASK: return ppufast.io.col.window.aboveMask;
|
case CGWSEL_COLORMASK: return ppufast.io.col.window.aboveMask;
|
||||||
case SNES_REG_CGWSEL_COLORSUBMASK: return ppufast.io.col.window.belowMask;
|
case CGWSEL_COLORSUBMASK: return ppufast.io.col.window.belowMask;
|
||||||
case SNES_REG_CGWSEL_ADDSUBMODE: return ppufast.io.col.blendMode;
|
case CGWSEL_ADDSUBMODE: return ppufast.io.col.blendMode;
|
||||||
case SNES_REG_CGWSEL_DIRECTCOLOR: return ppufast.io.col.directColor;
|
case CGWSEL_DIRECTCOLOR: return ppufast.io.col.directColor;
|
||||||
//$2101 OBSEL
|
//$2101 OBSEL
|
||||||
case SNES_REG_OBSEL_NAMEBASE: return ppufast.io.obj.tiledataAddress >> 13; // TODO: figure out why these shifts are only in specific places
|
case OBSEL_NAMEBASE: return ppufast.io.obj.tiledataAddress >> 13;
|
||||||
case SNES_REG_OBSEL_NAMESEL: return ppufast.io.obj.nameselect;
|
case OBSEL_NAMESEL: return ppufast.io.obj.nameselect;
|
||||||
case SNES_REG_OBSEL_SIZE: return ppufast.io.obj.baseSize;
|
case OBSEL_SIZE: return ppufast.io.obj.baseSize;
|
||||||
//$2131 CGADDSUB
|
//$2131 CGADDSUB
|
||||||
//enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
//enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||||
case SNES_REG_CGADDSUB_BG1: return ppufast.io.col.enable[PPUfast::Source::BG1];
|
case CGADDSUB_BG1: return ppufast.io.col.enable[PPUfast::Source::BG1];
|
||||||
case SNES_REG_CGADDSUB_BG2: return ppufast.io.col.enable[PPUfast::Source::BG2];
|
case CGADDSUB_BG2: return ppufast.io.col.enable[PPUfast::Source::BG2];
|
||||||
case SNES_REG_CGADDSUB_BG3: return ppufast.io.col.enable[PPUfast::Source::BG3];
|
case CGADDSUB_BG3: return ppufast.io.col.enable[PPUfast::Source::BG3];
|
||||||
case SNES_REG_CGADDSUB_BG4: return ppufast.io.col.enable[PPUfast::Source::BG4];
|
case CGADDSUB_BG4: return ppufast.io.col.enable[PPUfast::Source::BG4];
|
||||||
case SNES_REG_CGADDSUB_OBJ: return ppufast.io.col.enable[PPUfast::Source::OBJ2];
|
case CGADDSUB_OBJ: return ppufast.io.col.enable[PPUfast::Source::OBJ2];
|
||||||
case SNES_REG_CGADDSUB_BACKDROP: return ppufast.io.col.enable[PPUfast::Source::COL];
|
case CGADDSUB_BACKDROP: return ppufast.io.col.enable[PPUfast::Source::COL];
|
||||||
case SNES_REG_CGADDSUB_HALF: return ppufast.io.col.halve;
|
case CGADDSUB_HALF: return ppufast.io.col.halve;
|
||||||
case SNES_REG_CGADDSUB_MODE: return ppufast.io.col.mathMode;
|
case CGADDSUB_MODE: return ppufast.io.col.mathMode;
|
||||||
//$212C TM
|
//$212C TM
|
||||||
case SNES_REG_TM_BG1: return ppufast.io.bg1.aboveEnable;
|
case TM_BG1: return ppufast.io.bg1.aboveEnable;
|
||||||
case SNES_REG_TM_BG2: return ppufast.io.bg2.aboveEnable;
|
case TM_BG2: return ppufast.io.bg2.aboveEnable;
|
||||||
case SNES_REG_TM_BG3: return ppufast.io.bg3.aboveEnable;
|
case TM_BG3: return ppufast.io.bg3.aboveEnable;
|
||||||
case SNES_REG_TM_BG4: return ppufast.io.bg4.aboveEnable;
|
case TM_BG4: return ppufast.io.bg4.aboveEnable;
|
||||||
case SNES_REG_TM_OBJ: return ppufast.io.obj.aboveEnable;
|
case TM_OBJ: return ppufast.io.obj.aboveEnable;
|
||||||
//$212D TS
|
//$212D TS
|
||||||
case SNES_REG_TS_BG1: return ppufast.io.bg1.belowEnable;
|
case TS_BG1: return ppufast.io.bg1.belowEnable;
|
||||||
case SNES_REG_TS_BG2: return ppufast.io.bg2.belowEnable;
|
case TS_BG2: return ppufast.io.bg2.belowEnable;
|
||||||
case SNES_REG_TS_BG3: return ppufast.io.bg3.belowEnable;
|
case TS_BG3: return ppufast.io.bg3.belowEnable;
|
||||||
case SNES_REG_TS_BG4: return ppufast.io.bg4.belowEnable;
|
case TS_BG4: return ppufast.io.bg4.belowEnable;
|
||||||
case SNES_REG_TS_OBJ: return ppufast.io.obj.belowEnable;
|
case TS_OBJ: return ppufast.io.obj.belowEnable;
|
||||||
//Mode7 regs
|
//Mode7 regs
|
||||||
case SNES_REG_M7SEL_HFLIP: return ppufast.io.mode7.hflip;
|
case M7SEL_HFLIP: return ppufast.io.mode7.hflip;
|
||||||
case SNES_REG_M7SEL_VFLIP: return ppufast.io.mode7.vflip;
|
case M7SEL_VFLIP: return ppufast.io.mode7.vflip;
|
||||||
case SNES_REG_M7SEL_REPEAT: return ppufast.io.mode7.repeat;
|
case M7SEL_REPEAT: return ppufast.io.mode7.repeat;
|
||||||
case SNES_REG_M7A: return ppufast.io.mode7.a;
|
case M7A: return ppufast.io.mode7.a;
|
||||||
case SNES_REG_M7B: return ppufast.io.mode7.b;
|
case M7B: return ppufast.io.mode7.b;
|
||||||
case SNES_REG_M7C: return ppufast.io.mode7.c;
|
case M7C: return ppufast.io.mode7.c;
|
||||||
case SNES_REG_M7D: return ppufast.io.mode7.d;
|
case M7D: return ppufast.io.mode7.d;
|
||||||
case SNES_REG_M7X: return ppufast.io.mode7.x;
|
case M7X: return ppufast.io.mode7.x;
|
||||||
case SNES_REG_M7Y: return ppufast.io.mode7.y;
|
case M7Y: return ppufast.io.mode7.y;
|
||||||
//BG scroll regs
|
//BG scroll regs
|
||||||
case SNES_REG_BG1HOFS: return ppufast.io.bg1.hoffset;
|
case BG1HOFS: return ppufast.io.bg1.hoffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_BG1VOFS: return ppufast.io.bg1.voffset;
|
case BG1VOFS: return ppufast.io.bg1.voffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_BG2HOFS: return ppufast.io.bg2.hoffset;
|
case BG2HOFS: return ppufast.io.bg2.hoffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_BG2VOFS: return ppufast.io.bg2.voffset;
|
case BG2VOFS: return ppufast.io.bg2.voffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_BG3HOFS: return ppufast.io.bg3.hoffset;
|
case BG3HOFS: return ppufast.io.bg3.hoffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_BG3VOFS: return ppufast.io.bg3.voffset;
|
case BG3VOFS: return ppufast.io.bg3.voffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_BG4HOFS: return ppufast.io.bg4.hoffset;
|
case BG4HOFS: return ppufast.io.bg4.hoffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_BG4VOFS: return ppufast.io.bg4.voffset;
|
case BG4VOFS: return ppufast.io.bg4.voffset & 0x3FF; // copied from old bsnes impl; not sure why this & exists
|
||||||
case SNES_REG_M7HOFS: return ppufast.io.mode7.hoffset; // TODO figure out what that comment means .regs.m7_hofs & 0x1FFF; //rememebr to make these signed with <<19>>19
|
case M7HOFS: return ppufast.io.mode7.hoffset & 0x1FFF;
|
||||||
case SNES_REG_M7VOFS: return ppufast.io.mode7.voffset; //rememebr to make these signed with <<19>>19
|
case M7VOFS: return ppufast.io.mode7.voffset & 0x1FFF;
|
||||||
}
|
}
|
||||||
else; // no fast ppu
|
else; // no fast ppu
|
||||||
// TODO: potentially provide register values even in this case? currently all those are private in ppu.hpp
|
// TODO: potentially provide register values even in this case? currently all those are private in ppu.hpp
|
||||||
|
@ -386,8 +385,11 @@ EXPORT void* snes_get_memory_region(int id, int* size, int* word_size)
|
||||||
*size = sizeof(ppufast.vram);
|
*size = sizeof(ppufast.vram);
|
||||||
*word_size = sizeof(*ppufast.vram);
|
*word_size = sizeof(*ppufast.vram);
|
||||||
return ppufast.vram;
|
return ppufast.vram;
|
||||||
// case SNES_MEMORY::OAM: // probably weird since bsnes uses "object"s instead of bytes for oam rn
|
case SNES_MEMORY::OBJECTS: // returns a pointer to an array of "objects", not raw OAM memory
|
||||||
// return (uint8_t*) ppufast.objects;
|
if (!fast_ppu) break;
|
||||||
|
*size = sizeof(ppufast.objects);
|
||||||
|
*word_size = sizeof(*ppufast.objects);
|
||||||
|
return (void*) ppufast.objects;
|
||||||
case SNES_MEMORY::CGRAM:
|
case SNES_MEMORY::CGRAM:
|
||||||
if (!fast_ppu) break;
|
if (!fast_ppu) break;
|
||||||
*size = sizeof(ppufast.cgram);
|
*size = sizeof(ppufast.cgram);
|
||||||
|
|
|
@ -22,6 +22,7 @@ enum SNES_MEMORY {
|
||||||
WRAM,
|
WRAM,
|
||||||
APURAM,
|
APURAM,
|
||||||
VRAM,
|
VRAM,
|
||||||
|
OBJECTS,
|
||||||
CGRAM
|
CGRAM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,92 +57,89 @@ struct SnesRegisters
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// below code unused; would be useful for the graphics debugger
|
enum SNES_REGISTER {
|
||||||
//$2105
|
//$2105
|
||||||
#define SNES_REG_BG_MODE 0
|
BG_MODE,
|
||||||
#define SNES_REG_BG3_PRIORITY 1
|
BG3_PRIORITY,
|
||||||
#define SNES_REG_BG1_TILESIZE 2
|
BG1_TILESIZE,
|
||||||
#define SNES_REG_BG2_TILESIZE 3
|
BG2_TILESIZE,
|
||||||
#define SNES_REG_BG3_TILESIZE 4
|
BG3_TILESIZE,
|
||||||
#define SNES_REG_BG4_TILESIZE 5
|
BG4_TILESIZE,
|
||||||
//$2107
|
//$2107
|
||||||
#define SNES_REG_BG1_SCADDR 10
|
BG1_SCADDR,
|
||||||
#define SNES_REG_BG1_SCSIZE 11
|
BG1_SCSIZE,
|
||||||
//$2108
|
//$2108
|
||||||
#define SNES_REG_BG2_SCADDR 12
|
BG2_SCADDR,
|
||||||
#define SNES_REG_BG2_SCSIZE 13
|
BG2_SCSIZE,
|
||||||
//$2109
|
//$2109,
|
||||||
#define SNES_REG_BG3_SCADDR 14
|
BG3_SCADDR,
|
||||||
#define SNES_REG_BG3_SCSIZE 15
|
BG3_SCSIZE,
|
||||||
//$210A
|
//$210A
|
||||||
#define SNES_REG_BG4_SCADDR 16
|
BG4_SCADDR,
|
||||||
#define SNES_REG_BG4_SCSIZE 17
|
BG4_SCSIZE,
|
||||||
//$210B
|
//$210B
|
||||||
#define SNES_REG_BG1_TDADDR 20
|
BG1_TDADDR,
|
||||||
#define SNES_REG_BG2_TDADDR 21
|
BG2_TDADDR,
|
||||||
//$210C
|
//$210C
|
||||||
#define SNES_REG_BG3_TDADDR 22
|
BG3_TDADDR,
|
||||||
#define SNES_REG_BG4_TDADDR 23
|
BG4_TDADDR,
|
||||||
//$2133 SETINI
|
//$2133 SETINI
|
||||||
#define SNES_REG_SETINI_MODE7_EXTBG 30
|
SETINI_MODE7_EXTBG,
|
||||||
#define SNES_REG_SETINI_HIRES 31
|
SETINI_HIRES,
|
||||||
#define SNES_REG_SETINI_OVERSCAN 32
|
SETINI_OVERSCAN,
|
||||||
#define SNES_REG_SETINI_OBJ_INTERLACE 33
|
SETINI_OBJ_INTERLACE,
|
||||||
#define SNES_REG_SETINI_SCREEN_INTERLACE 34
|
SETINI_SCREEN_INTERLACE,
|
||||||
//$2130 CGWSEL
|
//$2130 CGWSEL
|
||||||
#define SNES_REG_CGWSEL_COLORMASK 40
|
CGWSEL_COLORMASK,
|
||||||
#define SNES_REG_CGWSEL_COLORSUBMASK 41
|
CGWSEL_COLORSUBMASK,
|
||||||
#define SNES_REG_CGWSEL_ADDSUBMODE 42
|
CGWSEL_ADDSUBMODE,
|
||||||
#define SNES_REG_CGWSEL_DIRECTCOLOR 43
|
CGWSEL_DIRECTCOLOR,
|
||||||
//$2101 OBSEL
|
//$2101 OBSEL
|
||||||
#define SNES_REG_OBSEL_NAMEBASE 50
|
OBSEL_NAMEBASE,
|
||||||
#define SNES_REG_OBSEL_NAMESEL 51
|
OBSEL_NAMESEL,
|
||||||
#define SNES_REG_OBSEL_SIZE 52
|
OBSEL_SIZE,
|
||||||
//$2131 CGADSUB
|
//$2131 CGADSUB
|
||||||
#define SNES_REG_CGADDSUB_MODE 60
|
CGADDSUB_MODE,
|
||||||
#define SNES_REG_CGADDSUB_HALF 61
|
CGADDSUB_HALF,
|
||||||
#define SNES_REG_CGADDSUB_BG4 62
|
CGADDSUB_BG4,
|
||||||
#define SNES_REG_CGADDSUB_BG3 63
|
CGADDSUB_BG3,
|
||||||
#define SNES_REG_CGADDSUB_BG2 64
|
CGADDSUB_BG2,
|
||||||
#define SNES_REG_CGADDSUB_BG1 65
|
CGADDSUB_BG1,
|
||||||
#define SNES_REG_CGADDSUB_OBJ 66
|
CGADDSUB_OBJ,
|
||||||
#define SNES_REG_CGADDSUB_BACKDROP 67
|
CGADDSUB_BACKDROP,
|
||||||
//$212C TM
|
//$212C TM
|
||||||
#define SNES_REG_TM_BG1 70
|
TM_BG1,
|
||||||
#define SNES_REG_TM_BG2 71
|
TM_BG2,
|
||||||
#define SNES_REG_TM_BG3 72
|
TM_BG3,
|
||||||
#define SNES_REG_TM_BG4 73
|
TM_BG4,
|
||||||
#define SNES_REG_TM_OBJ 74
|
TM_OBJ,
|
||||||
//$212D TM
|
//$212D TM
|
||||||
#define SNES_REG_TS_BG1 80
|
TS_BG1,
|
||||||
#define SNES_REG_TS_BG2 81
|
TS_BG2,
|
||||||
#define SNES_REG_TS_BG3 82
|
TS_BG3,
|
||||||
#define SNES_REG_TS_BG4 83
|
TS_BG4,
|
||||||
#define SNES_REG_TS_OBJ 84
|
TS_OBJ,
|
||||||
//Mode7 regs
|
//Mode7 regs
|
||||||
#define SNES_REG_M7SEL_REPEAT 90
|
M7SEL_REPEAT,
|
||||||
#define SNES_REG_M7SEL_HFLIP 91
|
M7SEL_HFLIP,
|
||||||
#define SNES_REG_M7SEL_VFLIP 92
|
M7SEL_VFLIP,
|
||||||
#define SNES_REG_M7A 93
|
M7A,
|
||||||
#define SNES_REG_M7B 94
|
M7B,
|
||||||
#define SNES_REG_M7C 95
|
M7C,
|
||||||
#define SNES_REG_M7D 96
|
M7D,
|
||||||
#define SNES_REG_M7X 97
|
M7X,
|
||||||
#define SNES_REG_M7Y 98
|
M7Y,
|
||||||
//BG scroll regs
|
//BG scroll regs
|
||||||
#define SNES_REG_BG1HOFS 100
|
BG1HOFS,
|
||||||
#define SNES_REG_BG1VOFS 101
|
BG1VOFS,
|
||||||
#define SNES_REG_BG2HOFS 102
|
BG2HOFS,
|
||||||
#define SNES_REG_BG2VOFS 103
|
BG2VOFS,
|
||||||
#define SNES_REG_BG3HOFS 104
|
BG3HOFS,
|
||||||
#define SNES_REG_BG3VOFS 105
|
BG3VOFS,
|
||||||
#define SNES_REG_BG4HOFS 106
|
BG4HOFS,
|
||||||
#define SNES_REG_BG4VOFS 107
|
BG4VOFS,
|
||||||
#define SNES_REG_M7HOFS 108
|
M7HOFS,
|
||||||
#define SNES_REG_M7VOFS 109
|
M7VOFS
|
||||||
|
};
|
||||||
|
|
||||||
int snes_peek_logical_register(int reg);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue