Remove most of (old) BSNES' managed source and callsites
This commit is contained in:
parent
fe85bfa41b
commit
3cc3440f22
|
@ -11,7 +11,6 @@ using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
|
using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
using BizHawk.Emulation.Cores.PCEngine;
|
using BizHawk.Emulation.Cores.PCEngine;
|
||||||
using BizHawk.Emulation.Cores.Sega.MasterSystem;
|
using BizHawk.Emulation.Cores.Sega.MasterSystem;
|
||||||
using BizHawk.Emulation.Cores.WonderSwan;
|
using BizHawk.Emulation.Cores.WonderSwan;
|
||||||
|
@ -195,7 +194,6 @@ namespace BizHawk.Client.Common
|
||||||
public object? GetSettings() => Emulator switch
|
public object? GetSettings() => Emulator switch
|
||||||
{
|
{
|
||||||
GPGX gpgx => gpgx.GetSettings(),
|
GPGX gpgx => gpgx.GetSettings(),
|
||||||
LibsnesCore snes => snes.GetSettings(),
|
|
||||||
NES nes => nes.GetSettings(),
|
NES nes => nes.GetSettings(),
|
||||||
NDS nds => nds.GetSettings(),
|
NDS nds => nds.GetSettings(),
|
||||||
PCEngine pce => pce.GetSettings(),
|
PCEngine pce => pce.GetSettings(),
|
||||||
|
@ -208,7 +206,6 @@ namespace BizHawk.Client.Common
|
||||||
public PutSettingsDirtyBits PutSettings(object settings) => Emulator switch
|
public PutSettingsDirtyBits PutSettings(object settings) => Emulator switch
|
||||||
{
|
{
|
||||||
GPGX gpgx => gpgx.PutSettings((GPGX.GPGXSettings) settings),
|
GPGX gpgx => gpgx.PutSettings((GPGX.GPGXSettings) settings),
|
||||||
LibsnesCore snes => snes.PutSettings((LibsnesCore.SnesSettings) settings),
|
|
||||||
NES nes => nes.PutSettings((NES.NESSettings) settings),
|
NES nes => nes.PutSettings((NES.NESSettings) settings),
|
||||||
NDS nds => nds.PutSettings((NDS.NDSSettings) settings),
|
NDS nds => nds.PutSettings((NDS.NDSSettings) settings),
|
||||||
PCEngine pce => pce.PutSettings((PCEngine.PCESettings) settings),
|
PCEngine pce => pce.PutSettings((PCEngine.PCESettings) settings),
|
||||||
|
@ -221,19 +218,6 @@ namespace BizHawk.Client.Common
|
||||||
public void SetRenderPlanes(params bool[] args)
|
public void SetRenderPlanes(params bool[] args)
|
||||||
{
|
{
|
||||||
static bool GetSetting(bool[] settings, int index) => index >= settings.Length || settings[index];
|
static bool GetSetting(bool[] settings, int index) => index >= settings.Length || settings[index];
|
||||||
void SetLibsnes(LibsnesCore core)
|
|
||||||
{
|
|
||||||
var s = core.GetSettings();
|
|
||||||
s.ShowBG1_0 = s.ShowBG1_1 = GetSetting(args, 0);
|
|
||||||
s.ShowBG2_0 = s.ShowBG2_1 = GetSetting(args, 1);
|
|
||||||
s.ShowBG3_0 = s.ShowBG3_1 = GetSetting(args, 2);
|
|
||||||
s.ShowBG4_0 = s.ShowBG4_1 = GetSetting(args, 3);
|
|
||||||
s.ShowOBJ_0 = GetSetting(args, 4);
|
|
||||||
s.ShowOBJ_1 = GetSetting(args, 5);
|
|
||||||
s.ShowOBJ_2 = GetSetting(args, 6);
|
|
||||||
s.ShowOBJ_3 = GetSetting(args, 7);
|
|
||||||
core.PutSettings(s);
|
|
||||||
}
|
|
||||||
void SetBsnes(ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> settingsProvider)
|
void SetBsnes(ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> settingsProvider)
|
||||||
{
|
{
|
||||||
var s = settingsProvider.GetSettings();
|
var s = settingsProvider.GetSettings();
|
||||||
|
@ -306,9 +290,6 @@ namespace BizHawk.Client.Common
|
||||||
case GPGX gpgx:
|
case GPGX gpgx:
|
||||||
SetGPGX(gpgx);
|
SetGPGX(gpgx);
|
||||||
break;
|
break;
|
||||||
case LibsnesCore snes:
|
|
||||||
SetLibsnes(snes);
|
|
||||||
break;
|
|
||||||
case BsnesCore bsnes:
|
case BsnesCore bsnes:
|
||||||
SetBsnes(bsnes);
|
SetBsnes(bsnes);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10,7 +10,6 @@ using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Cores;
|
using BizHawk.Emulation.Cores;
|
||||||
using BizHawk.Emulation.Cores.Libretro;
|
using BizHawk.Emulation.Cores.Libretro;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
|
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
using BizHawk.Emulation.Cores.Sony.PSX;
|
using BizHawk.Emulation.Cores.Sony.PSX;
|
||||||
using BizHawk.Emulation.Cores.Arcades.MAME;
|
using BizHawk.Emulation.Cores.Arcades.MAME;
|
||||||
using BizHawk.Emulation.DiscSystem;
|
using BizHawk.Emulation.DiscSystem;
|
||||||
|
@ -695,31 +694,11 @@ namespace BizHawk.Client.Common
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// need to get rid of this hack at some point
|
|
||||||
rom = new RomGame(file);
|
|
||||||
game = rom.GameInfo;
|
|
||||||
game.System = VSystemID.Raw.SNES;
|
|
||||||
nextEmulator = new LibsnesCore(
|
|
||||||
game,
|
|
||||||
null,
|
|
||||||
rom.FileData,
|
|
||||||
Path.GetDirectoryName(path.SubstringBefore('|')),
|
|
||||||
nextComm,
|
|
||||||
GetCoreSettings<LibsnesCore, LibsnesCore.SnesSettings>(),
|
|
||||||
GetCoreSyncSettings<LibsnesCore, LibsnesCore.SnesSyncSettings>()
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
{
|
||||||
DoLoadErrorCallback(ex.ToString(), VSystemID.Raw.GBL, LoadErrorType.Xml);
|
DoLoadErrorCallback(ex.ToString(), VSystemID.Raw.GBL, LoadErrorType.Xml);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadMAME(
|
private void LoadMAME(
|
||||||
string path,
|
string path,
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace BizHawk.Client.Common
|
||||||
([ VSystemID.Raw.GBL ],
|
([ VSystemID.Raw.GBL ],
|
||||||
[ CoreNames.GambatteLink, CoreNames.GBHawkLink, CoreNames.GBHawkLink3x, CoreNames.GBHawkLink4x ]),
|
[ CoreNames.GambatteLink, CoreNames.GBHawkLink, CoreNames.GBHawkLink3x, CoreNames.GBHawkLink4x ]),
|
||||||
([ VSystemID.Raw.SGB ],
|
([ VSystemID.Raw.SGB ],
|
||||||
[ CoreNames.Gambatte, CoreNames.Bsnes115, CoreNames.SubBsnes115, CoreNames.Bsnes ]),
|
[ CoreNames.Gambatte, CoreNames.Bsnes115, CoreNames.SubBsnes115 ]),
|
||||||
([ VSystemID.Raw.GEN ],
|
([ VSystemID.Raw.GEN ],
|
||||||
[ CoreNames.Gpgx, CoreNames.PicoDrive ]),
|
[ CoreNames.Gpgx, CoreNames.PicoDrive ]),
|
||||||
([ VSystemID.Raw.N64 ],
|
([ VSystemID.Raw.N64 ],
|
||||||
|
@ -49,7 +49,7 @@ namespace BizHawk.Client.Common
|
||||||
([ VSystemID.Raw.SMS, VSystemID.Raw.GG, VSystemID.Raw.SG ],
|
([ VSystemID.Raw.SMS, VSystemID.Raw.GG, VSystemID.Raw.SG ],
|
||||||
[ CoreNames.Gpgx, CoreNames.SMSHawk ]),
|
[ CoreNames.Gpgx, CoreNames.SMSHawk ]),
|
||||||
([ VSystemID.Raw.SNES ],
|
([ VSystemID.Raw.SNES ],
|
||||||
[ CoreNames.Snes9X, CoreNames.Bsnes115, CoreNames.SubBsnes115, CoreNames.Faust, CoreNames.Bsnes ]),
|
[ CoreNames.Snes9X, CoreNames.Bsnes115, CoreNames.SubBsnes115, CoreNames.Faust ]),
|
||||||
([ VSystemID.Raw.TI83 ],
|
([ VSystemID.Raw.TI83 ],
|
||||||
[ CoreNames.Emu83, CoreNames.TI83Hawk ]),
|
[ CoreNames.Emu83, CoreNames.TI83Hawk ]),
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,6 @@ using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.N64;
|
using BizHawk.Emulation.Cores.Nintendo.N64;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES9X;
|
using BizHawk.Emulation.Cores.Nintendo.SNES9X;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
|
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SubGBHawk;
|
using BizHawk.Emulation.Cores.Nintendo.SubGBHawk;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SubNESHawk;
|
using BizHawk.Emulation.Cores.Nintendo.SubNESHawk;
|
||||||
|
@ -734,12 +733,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private DialogResult OpenOldBSNESGamepadSettingsDialog(ISettingsAdapter settable)
|
|
||||||
{
|
|
||||||
using SNESControllerSettings form = new(settable);
|
|
||||||
return this.ShowDialogWithTempMute(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DialogResult OpenBSNESGamepadSettingsDialog(ISettingsAdapter settable)
|
private DialogResult OpenBSNESGamepadSettingsDialog(ISettingsAdapter settable)
|
||||||
{
|
{
|
||||||
using BSNESControllerSettings form = new(settable);
|
using BSNESControllerSettings form = new(settable);
|
||||||
|
@ -749,7 +742,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private void SNESControllerConfigurationMenuItem_Click(object sender, EventArgs e)
|
private void SNESControllerConfigurationMenuItem_Click(object sender, EventArgs e)
|
||||||
=> _ = Emulator switch
|
=> _ = Emulator switch
|
||||||
{
|
{
|
||||||
LibsnesCore => OpenOldBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<LibsnesCore>()),
|
|
||||||
BsnesCore => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<BsnesCore>()),
|
BsnesCore => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<BsnesCore>()),
|
||||||
SubBsnesCore => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<SubBsnesCore>()),
|
SubBsnesCore => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterForLoadedCore<SubBsnesCore>()),
|
||||||
_ => DialogResult.None
|
_ => DialogResult.None
|
||||||
|
@ -758,16 +750,12 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private void SnesGfxDebuggerMenuItem_Click(object sender, EventArgs e)
|
private void SnesGfxDebuggerMenuItem_Click(object sender, EventArgs e)
|
||||||
=> Tools.Load<SNESGraphicsDebugger>();
|
=> Tools.Load<SNESGraphicsDebugger>();
|
||||||
|
|
||||||
private DialogResult OpenOldBSNESSettingsDialog(ISettingsAdapter settable)
|
|
||||||
=> SNESOptions.DoSettingsDialog(this, settable);
|
|
||||||
|
|
||||||
private DialogResult OpenBSNESSettingsDialog(ISettingsAdapter settable)
|
private DialogResult OpenBSNESSettingsDialog(ISettingsAdapter settable)
|
||||||
=> BSNESOptions.DoSettingsDialog(this, settable);
|
=> BSNESOptions.DoSettingsDialog(this, settable);
|
||||||
|
|
||||||
private void SnesOptionsMenuItem_Click(object sender, EventArgs e)
|
private void SnesOptionsMenuItem_Click(object sender, EventArgs e)
|
||||||
=> _ = Emulator switch
|
=> _ = Emulator switch
|
||||||
{
|
{
|
||||||
LibsnesCore => OpenOldBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<LibsnesCore>()),
|
|
||||||
BsnesCore => OpenBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<BsnesCore>()),
|
BsnesCore => OpenBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<BsnesCore>()),
|
||||||
SubBsnesCore => OpenBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<SubBsnesCore>()),
|
SubBsnesCore => OpenBSNESSettingsDialog(GetSettingsAdapterForLoadedCore<SubBsnesCore>()),
|
||||||
_ => DialogResult.None
|
_ => DialogResult.None
|
||||||
|
@ -805,27 +793,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
settingsProvider.PutSettings(s);
|
settingsProvider.PutSettings(s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LibsnesCore libsnes:
|
|
||||||
{
|
|
||||||
var s = libsnes.GetSettings();
|
|
||||||
switch (layer)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
result = s.ShowBG1_0 = s.ShowBG1_1 = !s.ShowBG1_1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
result = s.ShowBG2_0 = s.ShowBG2_1 = !s.ShowBG2_1;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
result = s.ShowBG3_0 = s.ShowBG3_1 = !s.ShowBG3_1;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
result = s.ShowBG4_0 = s.ShowBG4_1 = !s.ShowBG4_1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
libsnes.PutSettings(s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Snes9x snes9X:
|
case Snes9x snes9X:
|
||||||
{
|
{
|
||||||
var s = snes9X.GetSettings();
|
var s = snes9X.GetSettings();
|
||||||
|
@ -1130,13 +1097,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
// Atari2600Hawk
|
// Atari2600Hawk
|
||||||
items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Atari2600Hawk, CreateGenericCoreConfigItem<Atari2600>(CoreNames.Atari2600Hawk)));
|
items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Atari2600Hawk, CreateGenericCoreConfigItem<Atari2600>(CoreNames.Atari2600Hawk)));
|
||||||
|
|
||||||
// BSNES
|
|
||||||
var oldBSNESGamepadSettingsItem = CreateSettingsItem("Controller Configuration...", (_, _) => OpenOldBSNESGamepadSettingsDialog(GetSettingsAdapterFor<LibsnesCore>()));
|
|
||||||
var oldBSNESSettingsItem = CreateSettingsItem("Options...", (_, _) => OpenOldBSNESSettingsDialog(GetSettingsAdapterFor<LibsnesCore>()));
|
|
||||||
var oldBSNESSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Bsnes, oldBSNESGamepadSettingsItem, oldBSNESSettingsItem);
|
|
||||||
oldBSNESSubmenu.DropDownOpened += (_, _) => oldBSNESGamepadSettingsItem.Enabled = MovieSession.Movie.NotActive() || Emulator is not LibsnesCore;
|
|
||||||
items.Add(oldBSNESSubmenu);
|
|
||||||
|
|
||||||
// BSNESv115+
|
// BSNESv115+
|
||||||
var bsnesGamepadSettingsItem = CreateSettingsItem("Controller Configuration...", (_, _) => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterFor<BsnesCore>()));
|
var bsnesGamepadSettingsItem = CreateSettingsItem("Controller Configuration...", (_, _) => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterFor<BsnesCore>()));
|
||||||
var bsnesSettingsItem = CreateSettingsItem("Options...", (_, _) => OpenBSNESSettingsDialog(GetSettingsAdapterFor<BsnesCore>()));
|
var bsnesSettingsItem = CreateSettingsItem("Options...", (_, _) => OpenBSNESSettingsDialog(GetSettingsAdapterFor<BsnesCore>()));
|
||||||
|
@ -1500,10 +1460,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
GBSubMenu.Visible = true;
|
GBSubMenu.Visible = true;
|
||||||
SameBoyColorChooserMenuItem.Visible = Emulator is Sameboy { IsCGBMode: false }; // palette config only works in DMG mode
|
SameBoyColorChooserMenuItem.Visible = Emulator is Sameboy { IsCGBMode: false }; // palette config only works in DMG mode
|
||||||
break;
|
break;
|
||||||
case VSystemID.Raw.SNES when Emulator is LibsnesCore oldBSNES: // doesn't use "SGB" sysID, always "SNES"
|
|
||||||
SNESSubMenu.Text = oldBSNES.IsSGB ? "&SGB" : "&SNES";
|
|
||||||
SNESSubMenu.Visible = true;
|
|
||||||
break;
|
|
||||||
case var _ when Emulator is BsnesCore or SubBsnesCore:
|
case var _ when Emulator is BsnesCore or SubBsnesCore:
|
||||||
SNESSubMenu.Text = $"&{sysID}";
|
SNESSubMenu.Text = $"&{sysID}";
|
||||||
SNESSubMenu.Visible = true;
|
SNESSubMenu.Visible = true;
|
||||||
|
|
|
@ -33,7 +33,6 @@ using BizHawk.Emulation.Cores.Consoles.SNK;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.GBA;
|
using BizHawk.Emulation.Cores.Nintendo.GBA;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.N64;
|
using BizHawk.Emulation.Cores.Nintendo.N64;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.DiscSystem;
|
using BizHawk.Emulation.DiscSystem;
|
||||||
|
|
||||||
|
@ -3532,12 +3531,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var name = Game.FilesystemSafeName();
|
var name = Game.FilesystemSafeName();
|
||||||
name += $".{Emulator.Attributes().CoreName}";
|
name += $".{Emulator.Attributes().CoreName}";
|
||||||
|
|
||||||
// Bsnes profiles have incompatible savestates so save the profile name
|
|
||||||
if (Emulator is LibsnesCore bsnes)
|
|
||||||
{
|
|
||||||
name += $".{bsnes.CurrentProfile}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MovieSession.Movie.IsActive())
|
if (MovieSession.Movie.IsActive())
|
||||||
{
|
{
|
||||||
name += $".{Path.GetFileNameWithoutExtension(MovieSession.Movie.Filename)}";
|
name += $".{Path.GetFileNameWithoutExtension(MovieSession.Movie.Filename)}";
|
||||||
|
@ -3731,7 +3724,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
InputManager.SyncControls(Emulator, MovieSession, Config);
|
InputManager.SyncControls(Emulator, MovieSession, Config);
|
||||||
_multiDiskMode = false;
|
_multiDiskMode = false;
|
||||||
|
|
||||||
if (oaOpenrom != null && Path.GetExtension(oaOpenrom.Path.Replace("|", "")).ToLowerInvariant() == ".xml" && Emulator is not LibsnesCore)
|
if (oaOpenrom != null && Path.GetExtension(oaOpenrom.Path.Replace("|", "")).ToLowerInvariant() == ".xml")
|
||||||
{
|
{
|
||||||
// this is a multi-disk bundler file
|
// this is a multi-disk bundler file
|
||||||
// determine the xml assets and create RomStatusDetails for all of them
|
// determine the xml assets and create RomStatusDetails for all of them
|
||||||
|
|
|
@ -4,7 +4,6 @@ using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
|
using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
|
||||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||||
using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive;
|
using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
@ -155,7 +154,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
VSystemID.Raw.SGX => ConsoleID.PCEngine, // ???
|
VSystemID.Raw.SGX => ConsoleID.PCEngine, // ???
|
||||||
VSystemID.Raw.SGXCD => ConsoleID.PCEngineCD, // ???
|
VSystemID.Raw.SGXCD => ConsoleID.PCEngineCD, // ???
|
||||||
VSystemID.Raw.SMS => ConsoleID.MasterSystem,
|
VSystemID.Raw.SMS => ConsoleID.MasterSystem,
|
||||||
VSystemID.Raw.SNES when Emu is LibsnesCore { IsSGB: true } => ConsoleID.GB,
|
|
||||||
VSystemID.Raw.SNES => ConsoleID.SNES,
|
VSystemID.Raw.SNES => ConsoleID.SNES,
|
||||||
VSystemID.Raw.TI83 => ConsoleID.TI83,
|
VSystemID.Raw.TI83 => ConsoleID.TI83,
|
||||||
VSystemID.Raw.TIC80 => ConsoleID.Tic80,
|
VSystemID.Raw.TIC80 => ConsoleID.Tic80,
|
||||||
|
|
|
@ -13,7 +13,6 @@ using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.GBA;
|
using BizHawk.Emulation.Cores.Nintendo.GBA;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
|
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES9X;
|
using BizHawk.Emulation.Cores.Nintendo.SNES9X;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SubGBHawk;
|
using BizHawk.Emulation.Cores.Nintendo.SubGBHawk;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SubNESHawk;
|
using BizHawk.Emulation.Cores.Nintendo.SubNESHawk;
|
||||||
|
@ -51,7 +50,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
[typeof(MGBAHawk)] = new[] { "DisplayBG0", "DisplayBG1", "DisplayBG2", "DisplayBG3", "DisplayOBJ" },
|
[typeof(MGBAHawk)] = new[] { "DisplayBG0", "DisplayBG1", "DisplayBG2", "DisplayBG3", "DisplayOBJ" },
|
||||||
[typeof(NES)] = new[] { "DispBackground", "DispSprites" },
|
[typeof(NES)] = new[] { "DispBackground", "DispSprites" },
|
||||||
[typeof(Sameboy)] = new[] { "EnableBGWIN", "EnableOBJ" },
|
[typeof(Sameboy)] = new[] { "EnableBGWIN", "EnableOBJ" },
|
||||||
[typeof(LibsnesCore)] = new[] { "ShowBG1_0", "ShowBG2_0", "ShowBG3_0", "ShowBG4_0", "ShowBG1_1", "ShowBG2_1", "ShowBG3_1", "ShowBG4_1", "ShowOBJ_0", "ShowOBJ_1", "ShowOBJ_2", "ShowOBJ_3" },
|
|
||||||
[typeof(Snes9x)] = new[] { "ShowBg0", "ShowBg1", "ShowBg2", "ShowBg3", "ShowSprites0", "ShowSprites1", "ShowSprites2", "ShowSprites3", "ShowWindow", "ShowTransparency" },
|
[typeof(Snes9x)] = new[] { "ShowBg0", "ShowBg1", "ShowBg2", "ShowBg3", "ShowSprites0", "ShowSprites1", "ShowSprites2", "ShowSprites3", "ShowWindow", "ShowTransparency" },
|
||||||
[typeof(PCEngine)] = new[] { "ShowBG1", "ShowOBJ1", "ShowBG2", "ShowOBJ2", },
|
[typeof(PCEngine)] = new[] { "ShowBG1", "ShowOBJ1", "ShowBG2", "ShowOBJ2", },
|
||||||
[typeof(GPGX)] = new[] { "DrawBGA", "DrawBGB", "DrawBGW", "DrawObj", },
|
[typeof(GPGX)] = new[] { "DrawBGA", "DrawBGB", "DrawBGW", "DrawObj", },
|
||||||
|
|
|
@ -1,196 +0,0 @@
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
partial class SNESControllerSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
this.OkBtn = new System.Windows.Forms.Button();
|
|
||||||
this.CancelBtn = new System.Windows.Forms.Button();
|
|
||||||
this.label1 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.label5 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.label4 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.Port2ComboBox = new System.Windows.Forms.ComboBox();
|
|
||||||
this.Port1ComboBox = new System.Windows.Forms.ComboBox();
|
|
||||||
this.MouseSpeedLabel1 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.LimitAnalogChangeCheckBox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.MouseSpeedLabel2 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.MouseSpeedLabel3 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.MouseNagLabel1 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.MouseNagLabel2 = new BizHawk.WinForms.Controls.LocLabelEx();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// OkBtn
|
|
||||||
//
|
|
||||||
this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.OkBtn.Location = new System.Drawing.Point(170, 264);
|
|
||||||
this.OkBtn.Name = "OkBtn";
|
|
||||||
this.OkBtn.Size = new System.Drawing.Size(60, 23);
|
|
||||||
this.OkBtn.TabIndex = 4;
|
|
||||||
this.OkBtn.Text = "&OK";
|
|
||||||
this.OkBtn.UseVisualStyleBackColor = true;
|
|
||||||
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
|
|
||||||
//
|
|
||||||
// CancelBtn
|
|
||||||
//
|
|
||||||
this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
|
||||||
this.CancelBtn.Location = new System.Drawing.Point(236, 264);
|
|
||||||
this.CancelBtn.Name = "CancelBtn";
|
|
||||||
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
|
|
||||||
this.CancelBtn.TabIndex = 5;
|
|
||||||
this.CancelBtn.Text = "&Cancel";
|
|
||||||
this.CancelBtn.UseVisualStyleBackColor = true;
|
|
||||||
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
|
|
||||||
//
|
|
||||||
// label1
|
|
||||||
//
|
|
||||||
this.label1.Location = new System.Drawing.Point(12, 9);
|
|
||||||
this.label1.Name = "label1";
|
|
||||||
this.label1.Text = "SNES Controller Settings";
|
|
||||||
//
|
|
||||||
// label5
|
|
||||||
//
|
|
||||||
this.label5.Location = new System.Drawing.Point(9, 88);
|
|
||||||
this.label5.Name = "label5";
|
|
||||||
this.label5.Text = "Port 2:";
|
|
||||||
//
|
|
||||||
// label4
|
|
||||||
//
|
|
||||||
this.label4.Location = new System.Drawing.Point(12, 38);
|
|
||||||
this.label4.Name = "label4";
|
|
||||||
this.label4.Text = "Port 1:";
|
|
||||||
//
|
|
||||||
// Port2ComboBox
|
|
||||||
//
|
|
||||||
this.Port2ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.Port2ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
|
||||||
this.Port2ComboBox.FormattingEnabled = true;
|
|
||||||
this.Port2ComboBox.Location = new System.Drawing.Point(12, 104);
|
|
||||||
this.Port2ComboBox.Name = "Port2ComboBox";
|
|
||||||
this.Port2ComboBox.Size = new System.Drawing.Size(284, 21);
|
|
||||||
this.Port2ComboBox.TabIndex = 20;
|
|
||||||
this.Port2ComboBox.SelectedIndexChanged += new System.EventHandler(this.PortComboBox_SelectedIndexChanged);
|
|
||||||
//
|
|
||||||
// Port1ComboBox
|
|
||||||
//
|
|
||||||
this.Port1ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.Port1ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
|
||||||
this.Port1ComboBox.FormattingEnabled = true;
|
|
||||||
this.Port1ComboBox.Location = new System.Drawing.Point(12, 54);
|
|
||||||
this.Port1ComboBox.Name = "Port1ComboBox";
|
|
||||||
this.Port1ComboBox.Size = new System.Drawing.Size(284, 21);
|
|
||||||
this.Port1ComboBox.TabIndex = 19;
|
|
||||||
this.Port1ComboBox.SelectedIndexChanged += new System.EventHandler(this.PortComboBox_SelectedIndexChanged);
|
|
||||||
//
|
|
||||||
// MouseSpeedLabel1
|
|
||||||
//
|
|
||||||
this.MouseSpeedLabel1.Location = new System.Drawing.Point(12, 195);
|
|
||||||
this.MouseSpeedLabel1.Name = "MouseSpeedLabel1";
|
|
||||||
this.MouseSpeedLabel1.Text = "For casual play this should be checked";
|
|
||||||
//
|
|
||||||
// LimitAnalogChangeCheckBox
|
|
||||||
//
|
|
||||||
this.LimitAnalogChangeCheckBox.AutoSize = true;
|
|
||||||
this.LimitAnalogChangeCheckBox.Location = new System.Drawing.Point(15, 175);
|
|
||||||
this.LimitAnalogChangeCheckBox.Name = "LimitAnalogChangeCheckBox";
|
|
||||||
this.LimitAnalogChangeCheckBox.Size = new System.Drawing.Size(173, 17);
|
|
||||||
this.LimitAnalogChangeCheckBox.TabIndex = 24;
|
|
||||||
this.LimitAnalogChangeCheckBox.Text = "Limit Analog Change Sensitivity";
|
|
||||||
this.LimitAnalogChangeCheckBox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// MouseSpeedLabel2
|
|
||||||
//
|
|
||||||
this.MouseSpeedLabel2.Location = new System.Drawing.Point(12, 208);
|
|
||||||
this.MouseSpeedLabel2.Name = "MouseSpeedLabel2";
|
|
||||||
this.MouseSpeedLabel2.Text = "The full range of values are rather unusuable in";
|
|
||||||
//
|
|
||||||
// MouseSpeedLabel3
|
|
||||||
//
|
|
||||||
this.MouseSpeedLabel3.Location = new System.Drawing.Point(12, 221);
|
|
||||||
this.MouseSpeedLabel3.Name = "MouseSpeedLabel3";
|
|
||||||
this.MouseSpeedLabel3.Text = "normal situations, but good if you need total control";
|
|
||||||
//
|
|
||||||
// MouseNagLabel1
|
|
||||||
//
|
|
||||||
this.MouseNagLabel1.Location = new System.Drawing.Point(12, 135);
|
|
||||||
this.MouseNagLabel1.Name = "MouseNagLabel1";
|
|
||||||
this.MouseNagLabel1.Text = "*Note: mouse and scope controls should be bound to an";
|
|
||||||
//
|
|
||||||
// MouseNagLabel2
|
|
||||||
//
|
|
||||||
this.MouseNagLabel2.Location = new System.Drawing.Point(45, 148);
|
|
||||||
this.MouseNagLabel2.Name = "MouseNagLabel2";
|
|
||||||
this.MouseNagLabel2.Text = "analog stick not the mouse";
|
|
||||||
//
|
|
||||||
// SNESControllerSettings
|
|
||||||
//
|
|
||||||
this.AcceptButton = this.OkBtn;
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.CancelButton = this.CancelBtn;
|
|
||||||
this.ClientSize = new System.Drawing.Size(308, 299);
|
|
||||||
this.Controls.Add(this.MouseNagLabel2);
|
|
||||||
this.Controls.Add(this.MouseNagLabel1);
|
|
||||||
this.Controls.Add(this.MouseSpeedLabel3);
|
|
||||||
this.Controls.Add(this.MouseSpeedLabel2);
|
|
||||||
this.Controls.Add(this.LimitAnalogChangeCheckBox);
|
|
||||||
this.Controls.Add(this.MouseSpeedLabel1);
|
|
||||||
this.Controls.Add(this.label5);
|
|
||||||
this.Controls.Add(this.label4);
|
|
||||||
this.Controls.Add(this.Port2ComboBox);
|
|
||||||
this.Controls.Add(this.Port1ComboBox);
|
|
||||||
this.Controls.Add(this.label1);
|
|
||||||
this.Controls.Add(this.CancelBtn);
|
|
||||||
this.Controls.Add(this.OkBtn);
|
|
||||||
this.Name = "SNESControllerSettings";
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
|
||||||
this.Text = "Controller Settings";
|
|
||||||
this.Load += new System.EventHandler(this.SNESControllerSettings_Load);
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
this.PerformLayout();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.Button OkBtn;
|
|
||||||
private System.Windows.Forms.Button CancelBtn;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx label1;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx label5;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx label4;
|
|
||||||
private System.Windows.Forms.ComboBox Port2ComboBox;
|
|
||||||
private System.Windows.Forms.ComboBox Port1ComboBox;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx MouseSpeedLabel1;
|
|
||||||
private System.Windows.Forms.CheckBox LimitAnalogChangeCheckBox;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx MouseSpeedLabel2;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx MouseSpeedLabel3;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx MouseNagLabel1;
|
|
||||||
private BizHawk.WinForms.Controls.LocLabelEx MouseNagLabel2;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
public partial class SNESControllerSettings : Form
|
|
||||||
{
|
|
||||||
private readonly ISettingsAdapter _settable;
|
|
||||||
|
|
||||||
private readonly LibsnesCore.SnesSyncSettings _syncSettings;
|
|
||||||
private bool _suppressDropdownChangeEvents;
|
|
||||||
|
|
||||||
public SNESControllerSettings(ISettingsAdapter settable)
|
|
||||||
{
|
|
||||||
_settable = settable;
|
|
||||||
_syncSettings = (LibsnesCore.SnesSyncSettings) _settable.GetSyncSettings();
|
|
||||||
InitializeComponent();
|
|
||||||
Icon = Properties.Resources.GameControllerIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SNESControllerSettings_Load(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
LimitAnalogChangeCheckBox.Checked = _syncSettings.LimitAnalogChangeSensitivity;
|
|
||||||
|
|
||||||
_suppressDropdownChangeEvents = true;
|
|
||||||
Port1ComboBox.PopulateFromEnum(_syncSettings.LeftPort);
|
|
||||||
Port2ComboBox.PopulateFromEnum(_syncSettings.RightPort);
|
|
||||||
_suppressDropdownChangeEvents = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OkBtn_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
bool changed =
|
|
||||||
_syncSettings.LeftPort.ToString() != Port1ComboBox.SelectedItem.ToString()
|
|
||||||
|| _syncSettings.RightPort.ToString() != Port2ComboBox.SelectedItem.ToString()
|
|
||||||
|| _syncSettings.LimitAnalogChangeSensitivity != LimitAnalogChangeCheckBox.Checked;
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
_syncSettings.LeftPort = (LibsnesControllerDeck.ControllerType)Enum.Parse(typeof(LibsnesControllerDeck.ControllerType), Port1ComboBox.SelectedItem.ToString());
|
|
||||||
_syncSettings.RightPort = (LibsnesControllerDeck.ControllerType)Enum.Parse(typeof(LibsnesControllerDeck.ControllerType), Port2ComboBox.SelectedItem.ToString());
|
|
||||||
_syncSettings.LimitAnalogChangeSensitivity = LimitAnalogChangeCheckBox.Checked;
|
|
||||||
|
|
||||||
_settable.PutCoreSyncSettings(_syncSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CancelBtn_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult = DialogResult.Cancel;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PortComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (!_suppressDropdownChangeEvents)
|
|
||||||
{
|
|
||||||
var leftPort = (LibsnesControllerDeck.ControllerType)Enum.Parse(typeof(LibsnesControllerDeck.ControllerType), Port1ComboBox.SelectedItem.ToString());
|
|
||||||
var rightPort = (LibsnesControllerDeck.ControllerType)Enum.Parse(typeof(LibsnesControllerDeck.ControllerType), Port2ComboBox.SelectedItem.ToString());
|
|
||||||
ToggleMouseSection(leftPort == LibsnesControllerDeck.ControllerType.Mouse
|
|
||||||
|| rightPort == LibsnesControllerDeck.ControllerType.Mouse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleMouseSection(bool show)
|
|
||||||
{
|
|
||||||
LimitAnalogChangeCheckBox.Visible =
|
|
||||||
MouseSpeedLabel1.Visible =
|
|
||||||
MouseSpeedLabel2.Visible =
|
|
||||||
MouseSpeedLabel3.Visible =
|
|
||||||
MouseNagLabel1.Visible =
|
|
||||||
MouseNagLabel2.Visible =
|
|
||||||
show;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
</root>
|
|
|
@ -1,270 +0,0 @@
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
partial class SNESOptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
this.btnOk = new System.Windows.Forms.Button();
|
|
||||||
this.btnCancel = new System.Windows.Forms.Button();
|
|
||||||
this.cbDoubleSize = new System.Windows.Forms.CheckBox();
|
|
||||||
this.lblDoubleSize = new BizHawk.WinForms.Controls.LocSzLabelEx();
|
|
||||||
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
|
||||||
this.cbCropSGBFrame = new System.Windows.Forms.CheckBox();
|
|
||||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
|
||||||
this.Bg4Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.Bg3Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.Bg2Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.Bg1Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.Obj4Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.Obj3Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.Obj2Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.Obj1Checkbox = new System.Windows.Forms.CheckBox();
|
|
||||||
this.cbRandomizedInitialState = new System.Windows.Forms.CheckBox();
|
|
||||||
this.groupBox1.SuspendLayout();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// btnOk
|
|
||||||
//
|
|
||||||
this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.btnOk.Location = new System.Drawing.Point(136, 303);
|
|
||||||
this.btnOk.Name = "btnOk";
|
|
||||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
|
||||||
this.btnOk.TabIndex = 0;
|
|
||||||
this.btnOk.Text = "OK";
|
|
||||||
this.btnOk.UseVisualStyleBackColor = true;
|
|
||||||
this.btnOk.Click += new System.EventHandler(this.BtnOk_Click);
|
|
||||||
//
|
|
||||||
// btnCancel
|
|
||||||
//
|
|
||||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
|
||||||
this.btnCancel.Location = new System.Drawing.Point(217, 303);
|
|
||||||
this.btnCancel.Name = "btnCancel";
|
|
||||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
|
||||||
this.btnCancel.TabIndex = 1;
|
|
||||||
this.btnCancel.Text = "Cancel";
|
|
||||||
this.btnCancel.UseVisualStyleBackColor = true;
|
|
||||||
this.btnCancel.Click += new System.EventHandler(this.BtnCancel_Click);
|
|
||||||
//
|
|
||||||
// cbDoubleSize
|
|
||||||
//
|
|
||||||
this.cbDoubleSize.AutoSize = true;
|
|
||||||
this.cbDoubleSize.Location = new System.Drawing.Point(18, 20);
|
|
||||||
this.cbDoubleSize.Name = "cbDoubleSize";
|
|
||||||
this.cbDoubleSize.Size = new System.Drawing.Size(178, 17);
|
|
||||||
this.cbDoubleSize.TabIndex = 6;
|
|
||||||
this.cbDoubleSize.Text = "Always Double-Size Framebuffer";
|
|
||||||
this.cbDoubleSize.UseVisualStyleBackColor = true;
|
|
||||||
this.cbDoubleSize.CheckedChanged += new System.EventHandler(this.CbDoubleSize_CheckedChanged);
|
|
||||||
//
|
|
||||||
// lblDoubleSize
|
|
||||||
//
|
|
||||||
this.lblDoubleSize.Location = new System.Drawing.Point(36, 41);
|
|
||||||
this.lblDoubleSize.Name = "lblDoubleSize";
|
|
||||||
this.lblDoubleSize.Size = new System.Drawing.Size(254, 57);
|
|
||||||
this.lblDoubleSize.Text = "Some games are changing the resolution constantly (e.g. SD3) so this option can f" +
|
|
||||||
"orce the SNES output to stay double-size always. NOTE: The Accuracy core runs as" +
|
|
||||||
" if this is selected.\r\n";
|
|
||||||
//
|
|
||||||
// radioButton1
|
|
||||||
//
|
|
||||||
this.radioButton1.AutoSize = true;
|
|
||||||
this.radioButton1.Location = new System.Drawing.Point(37, 46);
|
|
||||||
this.radioButton1.Name = "radioButton1";
|
|
||||||
this.radioButton1.Size = new System.Drawing.Size(202, 17);
|
|
||||||
this.radioButton1.TabIndex = 9;
|
|
||||||
this.radioButton1.TabStop = true;
|
|
||||||
this.radioButton1.Text = "Performance (only for casual gaming!)";
|
|
||||||
this.radioButton1.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// cbCropSGBFrame
|
|
||||||
//
|
|
||||||
this.cbCropSGBFrame.AutoSize = true;
|
|
||||||
this.cbCropSGBFrame.Location = new System.Drawing.Point(15, 110);
|
|
||||||
this.cbCropSGBFrame.Name = "cbCropSGBFrame";
|
|
||||||
this.cbCropSGBFrame.Size = new System.Drawing.Size(105, 17);
|
|
||||||
this.cbCropSGBFrame.TabIndex = 10;
|
|
||||||
this.cbCropSGBFrame.Text = "Crop SGB Frame";
|
|
||||||
this.cbCropSGBFrame.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// groupBox1
|
|
||||||
//
|
|
||||||
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.groupBox1.Controls.Add(this.Bg4Checkbox);
|
|
||||||
this.groupBox1.Controls.Add(this.Bg3Checkbox);
|
|
||||||
this.groupBox1.Controls.Add(this.Bg2Checkbox);
|
|
||||||
this.groupBox1.Controls.Add(this.Bg1Checkbox);
|
|
||||||
this.groupBox1.Controls.Add(this.Obj4Checkbox);
|
|
||||||
this.groupBox1.Controls.Add(this.Obj3Checkbox);
|
|
||||||
this.groupBox1.Controls.Add(this.Obj2Checkbox);
|
|
||||||
this.groupBox1.Controls.Add(this.Obj1Checkbox);
|
|
||||||
this.groupBox1.Location = new System.Drawing.Point(18, 165);
|
|
||||||
this.groupBox1.Name = "groupBox1";
|
|
||||||
this.groupBox1.Size = new System.Drawing.Size(274, 132);
|
|
||||||
this.groupBox1.TabIndex = 11;
|
|
||||||
this.groupBox1.TabStop = false;
|
|
||||||
this.groupBox1.Text = "Display";
|
|
||||||
//
|
|
||||||
// Bg4Checkbox
|
|
||||||
//
|
|
||||||
this.Bg4Checkbox.AutoSize = true;
|
|
||||||
this.Bg4Checkbox.Location = new System.Drawing.Point(150, 98);
|
|
||||||
this.Bg4Checkbox.Name = "Bg4Checkbox";
|
|
||||||
this.Bg4Checkbox.Size = new System.Drawing.Size(50, 17);
|
|
||||||
this.Bg4Checkbox.TabIndex = 7;
|
|
||||||
this.Bg4Checkbox.Text = "BG 4";
|
|
||||||
this.Bg4Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// Bg3Checkbox
|
|
||||||
//
|
|
||||||
this.Bg3Checkbox.AutoSize = true;
|
|
||||||
this.Bg3Checkbox.Location = new System.Drawing.Point(150, 75);
|
|
||||||
this.Bg3Checkbox.Name = "Bg3Checkbox";
|
|
||||||
this.Bg3Checkbox.Size = new System.Drawing.Size(50, 17);
|
|
||||||
this.Bg3Checkbox.TabIndex = 6;
|
|
||||||
this.Bg3Checkbox.Text = "BG 3";
|
|
||||||
this.Bg3Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// Bg2Checkbox
|
|
||||||
//
|
|
||||||
this.Bg2Checkbox.AutoSize = true;
|
|
||||||
this.Bg2Checkbox.Location = new System.Drawing.Point(150, 52);
|
|
||||||
this.Bg2Checkbox.Name = "Bg2Checkbox";
|
|
||||||
this.Bg2Checkbox.Size = new System.Drawing.Size(50, 17);
|
|
||||||
this.Bg2Checkbox.TabIndex = 5;
|
|
||||||
this.Bg2Checkbox.Text = "BG 2";
|
|
||||||
this.Bg2Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// Bg1Checkbox
|
|
||||||
//
|
|
||||||
this.Bg1Checkbox.AutoSize = true;
|
|
||||||
this.Bg1Checkbox.Location = new System.Drawing.Point(150, 29);
|
|
||||||
this.Bg1Checkbox.Name = "Bg1Checkbox";
|
|
||||||
this.Bg1Checkbox.Size = new System.Drawing.Size(50, 17);
|
|
||||||
this.Bg1Checkbox.TabIndex = 4;
|
|
||||||
this.Bg1Checkbox.Text = "BG 1";
|
|
||||||
this.Bg1Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// Obj4Checkbox
|
|
||||||
//
|
|
||||||
this.Obj4Checkbox.AutoSize = true;
|
|
||||||
this.Obj4Checkbox.Location = new System.Drawing.Point(21, 98);
|
|
||||||
this.Obj4Checkbox.Name = "Obj4Checkbox";
|
|
||||||
this.Obj4Checkbox.Size = new System.Drawing.Size(55, 17);
|
|
||||||
this.Obj4Checkbox.TabIndex = 3;
|
|
||||||
this.Obj4Checkbox.Text = "OBJ 4";
|
|
||||||
this.Obj4Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// Obj3Checkbox
|
|
||||||
//
|
|
||||||
this.Obj3Checkbox.AutoSize = true;
|
|
||||||
this.Obj3Checkbox.Location = new System.Drawing.Point(21, 75);
|
|
||||||
this.Obj3Checkbox.Name = "Obj3Checkbox";
|
|
||||||
this.Obj3Checkbox.Size = new System.Drawing.Size(55, 17);
|
|
||||||
this.Obj3Checkbox.TabIndex = 2;
|
|
||||||
this.Obj3Checkbox.Text = "OBJ 3";
|
|
||||||
this.Obj3Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// Obj2Checkbox
|
|
||||||
//
|
|
||||||
this.Obj2Checkbox.AutoSize = true;
|
|
||||||
this.Obj2Checkbox.Location = new System.Drawing.Point(22, 52);
|
|
||||||
this.Obj2Checkbox.Name = "Obj2Checkbox";
|
|
||||||
this.Obj2Checkbox.Size = new System.Drawing.Size(55, 17);
|
|
||||||
this.Obj2Checkbox.TabIndex = 1;
|
|
||||||
this.Obj2Checkbox.Text = "OBJ 2";
|
|
||||||
this.Obj2Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// Obj1Checkbox
|
|
||||||
//
|
|
||||||
this.Obj1Checkbox.AutoSize = true;
|
|
||||||
this.Obj1Checkbox.Location = new System.Drawing.Point(21, 29);
|
|
||||||
this.Obj1Checkbox.Name = "Obj1Checkbox";
|
|
||||||
this.Obj1Checkbox.Size = new System.Drawing.Size(55, 17);
|
|
||||||
this.Obj1Checkbox.TabIndex = 0;
|
|
||||||
this.Obj1Checkbox.Text = "OBJ 1";
|
|
||||||
this.Obj1Checkbox.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// cbRandomizedInitialState
|
|
||||||
//
|
|
||||||
this.cbRandomizedInitialState.AutoSize = true;
|
|
||||||
this.cbRandomizedInitialState.Location = new System.Drawing.Point(15, 133);
|
|
||||||
this.cbRandomizedInitialState.Name = "cbRandomizedInitialState";
|
|
||||||
this.cbRandomizedInitialState.Size = new System.Drawing.Size(140, 17);
|
|
||||||
this.cbRandomizedInitialState.TabIndex = 12;
|
|
||||||
this.cbRandomizedInitialState.Text = "Randomized Initial State";
|
|
||||||
this.cbRandomizedInitialState.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// SNESOptions
|
|
||||||
//
|
|
||||||
this.AcceptButton = this.btnOk;
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.CancelButton = this.btnCancel;
|
|
||||||
this.ClientSize = new System.Drawing.Size(304, 338);
|
|
||||||
this.Controls.Add(this.cbRandomizedInitialState);
|
|
||||||
this.Controls.Add(this.groupBox1);
|
|
||||||
this.Controls.Add(this.cbCropSGBFrame);
|
|
||||||
this.Controls.Add(this.lblDoubleSize);
|
|
||||||
this.Controls.Add(this.cbDoubleSize);
|
|
||||||
this.Controls.Add(this.btnCancel);
|
|
||||||
this.Controls.Add(this.btnOk);
|
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
|
||||||
this.MaximizeBox = false;
|
|
||||||
this.MinimizeBox = false;
|
|
||||||
this.Name = "SNESOptions";
|
|
||||||
this.ShowIcon = false;
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
|
||||||
this.Text = "BSNES Options";
|
|
||||||
this.groupBox1.ResumeLayout(false);
|
|
||||||
this.groupBox1.PerformLayout();
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
this.PerformLayout();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.Button btnOk;
|
|
||||||
private System.Windows.Forms.Button btnCancel;
|
|
||||||
private System.Windows.Forms.CheckBox cbDoubleSize;
|
|
||||||
private BizHawk.WinForms.Controls.LocSzLabelEx lblDoubleSize;
|
|
||||||
private System.Windows.Forms.RadioButton radioButton1;
|
|
||||||
private System.Windows.Forms.CheckBox cbCropSGBFrame;
|
|
||||||
private System.Windows.Forms.GroupBox groupBox1;
|
|
||||||
private System.Windows.Forms.CheckBox Bg4Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox Bg3Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox Bg2Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox Bg1Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox Obj4Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox Obj3Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox Obj2Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox Obj1Checkbox;
|
|
||||||
private System.Windows.Forms.CheckBox cbRandomizedInitialState;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,119 +0,0 @@
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
|
||||||
{
|
|
||||||
public partial class SNESOptions : Form
|
|
||||||
{
|
|
||||||
private SNESOptions()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _suppressDoubleSize;
|
|
||||||
private bool _userDoubleSizeOption;
|
|
||||||
|
|
||||||
public static DialogResult DoSettingsDialog(IDialogParent dialogParent, ISettingsAdapter settable)
|
|
||||||
{
|
|
||||||
var s = (LibsnesCore.SnesSettings) settable.GetSettings();
|
|
||||||
var ss = (LibsnesCore.SnesSyncSettings) settable.GetSyncSettings();
|
|
||||||
using var dlg = new SNESOptions
|
|
||||||
{
|
|
||||||
RandomizedInitialState = ss.RandomizedInitialState,
|
|
||||||
AlwaysDoubleSize = s.AlwaysDoubleSize,
|
|
||||||
CropSGBFrame = s.CropSGBFrame,
|
|
||||||
ShowObj1 = s.ShowOBJ_0,
|
|
||||||
ShowObj2 = s.ShowOBJ_1,
|
|
||||||
ShowObj3 = s.ShowOBJ_2,
|
|
||||||
ShowObj4 = s.ShowOBJ_3,
|
|
||||||
ShowBg1 = s.ShowBG1_0,
|
|
||||||
ShowBg2 = s.ShowBG2_0,
|
|
||||||
ShowBg3 = s.ShowBG3_0,
|
|
||||||
ShowBg4 = s.ShowBG4_0
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = dialogParent.ShowDialogAsChild(dlg);
|
|
||||||
if (!result.IsOk()) return result;
|
|
||||||
|
|
||||||
s.AlwaysDoubleSize = dlg.AlwaysDoubleSize;
|
|
||||||
s.CropSGBFrame = dlg.CropSGBFrame;
|
|
||||||
ss.RandomizedInitialState = dlg.RandomizedInitialState;
|
|
||||||
s.ShowOBJ_0 = dlg.ShowObj1;
|
|
||||||
s.ShowOBJ_1 = dlg.ShowObj2;
|
|
||||||
s.ShowOBJ_2 = dlg.ShowObj3;
|
|
||||||
s.ShowOBJ_3 = dlg.ShowObj4;
|
|
||||||
s.ShowBG1_0 = s.ShowBG1_1 = dlg.ShowBg1;
|
|
||||||
s.ShowBG2_0 = s.ShowBG2_1 = dlg.ShowBg2;
|
|
||||||
s.ShowBG3_0 = s.ShowBG3_1 = dlg.ShowBg3;
|
|
||||||
s.ShowBG4_0 = s.ShowBG4_1 = dlg.ShowBg4;
|
|
||||||
settable.PutCoreSettings(s);
|
|
||||||
settable.PutCoreSyncSettings(ss);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AlwaysDoubleSize
|
|
||||||
{
|
|
||||||
get => _userDoubleSizeOption;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_userDoubleSizeOption = value;
|
|
||||||
RefreshDoubleSizeOption();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CropSGBFrame
|
|
||||||
{
|
|
||||||
get => cbCropSGBFrame.Checked;
|
|
||||||
set => cbCropSGBFrame.Checked = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool RandomizedInitialState
|
|
||||||
{
|
|
||||||
get => cbRandomizedInitialState.Checked;
|
|
||||||
set => cbRandomizedInitialState.Checked = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ShowObj1 { get => Obj1Checkbox.Checked; set => Obj1Checkbox.Checked = value;
|
|
||||||
}
|
|
||||||
private bool ShowObj2 { get => Obj2Checkbox.Checked; set => Obj2Checkbox.Checked = value; }
|
|
||||||
private bool ShowObj3 { get => Obj3Checkbox.Checked; set => Obj3Checkbox.Checked = value; }
|
|
||||||
private bool ShowObj4 { get => Obj4Checkbox.Checked; set => Obj4Checkbox.Checked = value; }
|
|
||||||
|
|
||||||
private bool ShowBg1 { get => Bg1Checkbox.Checked; set => Bg1Checkbox.Checked = value; }
|
|
||||||
private bool ShowBg2 { get => Bg2Checkbox.Checked; set => Bg2Checkbox.Checked = value; }
|
|
||||||
private bool ShowBg3 { get => Bg3Checkbox.Checked; set => Bg3Checkbox.Checked = value; }
|
|
||||||
private bool ShowBg4 { get => Bg4Checkbox.Checked; set => Bg4Checkbox.Checked = value; }
|
|
||||||
|
|
||||||
private void RefreshDoubleSizeOption()
|
|
||||||
{
|
|
||||||
_suppressDoubleSize = true;
|
|
||||||
cbDoubleSize.Checked = !cbDoubleSize.Enabled || _userDoubleSizeOption;
|
|
||||||
_suppressDoubleSize = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CbDoubleSize_CheckedChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (_suppressDoubleSize)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_userDoubleSizeOption = cbDoubleSize.Checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnOk_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnCancel_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult = DialogResult.Cancel;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
</root>
|
|
|
@ -1207,7 +1207,6 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
#if false
|
#if false
|
||||||
//TODO
|
//TODO
|
||||||
LibsnesApi dll = TODO;
|
|
||||||
dll.QUERY_set_backdropColor(DecodeWinformsColorToSNES(checkBackdropColor.Checked ? pnBackdropColor.BackColor : Color.FromArgb(-1)));
|
dll.QUERY_set_backdropColor(DecodeWinformsColorToSNES(checkBackdropColor.Checked ? pnBackdropColor.BackColor : Color.FromArgb(-1)));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,6 @@
|
||||||
<Compile Update="Consoles/Nintendo/SubNESHawk/SubNESHawk.*.cs" DependentUpon="SubNESHawk.cs" />
|
<Compile Update="Consoles/Nintendo/SubNESHawk/SubNESHawk.*.cs" DependentUpon="SubNESHawk.cs" />
|
||||||
<Compile Update="Consoles/Nintendo/QuickNES/QuickNES.*.cs" DependentUpon="QuickNES.cs" />
|
<Compile Update="Consoles/Nintendo/QuickNES/QuickNES.*.cs" DependentUpon="QuickNES.cs" />
|
||||||
<Compile Update="Consoles/Nintendo/Sameboy/SameBoy.*.cs" DependentUpon="SameBoy.cs" />
|
<Compile Update="Consoles/Nintendo/Sameboy/SameBoy.*.cs" DependentUpon="SameBoy.cs" />
|
||||||
<Compile Update="Consoles/Nintendo/SNES/LibsnesCore.*.cs" DependentUpon="LibsnesCore.cs" />
|
|
||||||
<Compile Update="Consoles/PC Engine/PCEngine.*.cs" DependentUpon="PCEngine.cs" />
|
<Compile Update="Consoles/PC Engine/PCEngine.*.cs" DependentUpon="PCEngine.cs" />
|
||||||
<Compile Update="Consoles/Sega/GGHawkLink/GGHawkLink.*.cs" DependentUpon="GGHawkLink.cs" />
|
<Compile Update="Consoles/Sega/GGHawkLink/GGHawkLink.*.cs" DependentUpon="GGHawkLink.cs" />
|
||||||
<Compile Update="Consoles/Sega/gpgx64/GPGX.*.cs" DependentUpon="GPGX.cs" />
|
<Compile Update="Consoles/Sega/gpgx64/GPGX.*.cs" DependentUpon="GPGX.cs" />
|
||||||
|
|
|
@ -1,448 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Emulation.Cores.Waterbox;
|
|
||||||
using BizHawk.BizInvoke;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public abstract unsafe class CoreImpl
|
|
||||||
{
|
|
||||||
[BizImport(CallingConvention.Cdecl, Compatibility = true)]
|
|
||||||
public abstract IntPtr DllInit();
|
|
||||||
[BizImport(CallingConvention.Cdecl, Compatibility = true)]
|
|
||||||
public abstract void Message(LibsnesApi.eMessage msg);
|
|
||||||
[BizImport(CallingConvention.Cdecl, Compatibility = true)]
|
|
||||||
public abstract void CopyBuffer(int id, void* ptr, int size);
|
|
||||||
[BizImport(CallingConvention.Cdecl, Compatibility = true)]
|
|
||||||
public abstract void SetBuffer(int id, void* ptr, int size);
|
|
||||||
[BizImport(CallingConvention.Cdecl)]
|
|
||||||
public abstract void PostLoadState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe partial class LibsnesApi : IDisposable, IMonitor, IStatable
|
|
||||||
{
|
|
||||||
static LibsnesApi()
|
|
||||||
{
|
|
||||||
if (sizeof(CommStruct) != 368)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("sizeof(comm)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private WaterboxHost _exe;
|
|
||||||
private CoreImpl _core;
|
|
||||||
private bool _disposed;
|
|
||||||
private CommStruct* _comm;
|
|
||||||
private readonly Dictionary<string, IntPtr> _sharedMemoryBlocks = new Dictionary<string, IntPtr>();
|
|
||||||
private bool _sealed = false;
|
|
||||||
|
|
||||||
public void Enter()
|
|
||||||
{
|
|
||||||
_exe.Enter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Exit()
|
|
||||||
{
|
|
||||||
_exe.Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly List<string> _readonlyFiles = new List<string>();
|
|
||||||
|
|
||||||
public void AddReadonlyFile(byte[] data, string name)
|
|
||||||
{
|
|
||||||
_exe.AddReadonlyFile(data, name);
|
|
||||||
_readonlyFiles.Add(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibsnesApi(string dllPath, CoreComm comm, IEnumerable<Delegate> allCallbacks)
|
|
||||||
{
|
|
||||||
_exe = new WaterboxHost(new WaterboxOptions
|
|
||||||
{
|
|
||||||
Filename = "libsnes.wbx",
|
|
||||||
Path = dllPath,
|
|
||||||
SbrkHeapSizeKB = 4 * 1024,
|
|
||||||
InvisibleHeapSizeKB = 8 * 1024,
|
|
||||||
MmapHeapSizeKB = 32 * 1024, // TODO: see if we can safely make libco stacks smaller
|
|
||||||
PlainHeapSizeKB = 32 * 1024, // TODO: This can be smaller, probably; needs to be as big as largest ROM + 2MB, or less
|
|
||||||
SealedHeapSizeKB = 80 * 1024,
|
|
||||||
SkipCoreConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
|
|
||||||
SkipMemoryConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
|
|
||||||
});
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
// Marshal checks that function pointers passed to GetDelegateForFunctionPointer are
|
|
||||||
// _currently_ valid when created, even though they don't need to be valid until
|
|
||||||
// the delegate is later invoked. so GetInvoker needs to be acquired within a lock.
|
|
||||||
_core = BizInvoker.GetInvoker<CoreImpl>(_exe, _exe, CallingConventionAdapters.MakeWaterbox(allCallbacks, _exe));
|
|
||||||
_comm = (CommStruct*)_core.DllInit().ToPointer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (!_disposed)
|
|
||||||
{
|
|
||||||
_disposed = true;
|
|
||||||
_exe.Dispose();
|
|
||||||
_exe = null;
|
|
||||||
_core = null;
|
|
||||||
_comm = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copy an ascii string into libretro. It keeps the copy.
|
|
||||||
/// </summary>
|
|
||||||
public void CopyAscii(int id, string str)
|
|
||||||
{
|
|
||||||
fixed (byte* cp = System.Text.Encoding.ASCII.GetBytes(str + "\0"))
|
|
||||||
{
|
|
||||||
_core.CopyBuffer(id, cp, str.Length + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copy a buffer into libretro. It keeps the copy.
|
|
||||||
/// </summary>
|
|
||||||
public void CopyBytes(int id, byte[] bytes)
|
|
||||||
{
|
|
||||||
fixed (byte* bp = bytes)
|
|
||||||
{
|
|
||||||
_core.CopyBuffer(id, bp, bytes.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Locks a buffer and sets it into libretro. You must pass a delegate to be executed while that buffer is locked.
|
|
||||||
/// This is meant to be used for avoiding a memcpy for large roms (which the core is then just going to memcpy again on its own)
|
|
||||||
/// The memcpy has to happen at some point (libretro semantics specify [not literally, the docs don't say] that the core should finish using the buffer before its init returns)
|
|
||||||
/// but this limits it to once.
|
|
||||||
/// Moreover, this keeps the c++ side from having to free strings when they're no longer used (and memory management is trickier there, so we try to avoid it)
|
|
||||||
/// </summary>
|
|
||||||
public void SetBytes(int id, byte[] bytes, Action andThen)
|
|
||||||
{
|
|
||||||
if (_sealed)
|
|
||||||
throw new InvalidOperationException("Init period is over");
|
|
||||||
fixed (byte* bp = bytes)
|
|
||||||
{
|
|
||||||
_core.SetBuffer(id, bp, bytes.Length);
|
|
||||||
andThen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// see SetBytes
|
|
||||||
/// </summary>
|
|
||||||
public void SetAscii(int id, string str, Action andThen)
|
|
||||||
{
|
|
||||||
if (_sealed)
|
|
||||||
throw new InvalidOperationException("Init period is over");
|
|
||||||
fixed (byte* cp = System.Text.Encoding.ASCII.GetBytes(str + "\0"))
|
|
||||||
{
|
|
||||||
_core.SetBuffer(id, cp, str.Length + 1);
|
|
||||||
andThen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action<uint> ReadHook, ExecHook;
|
|
||||||
public Action<uint, byte> WriteHook;
|
|
||||||
|
|
||||||
public Action<uint> ReadHook_SMP, ExecHook_SMP;
|
|
||||||
public Action<uint, byte> WriteHook_SMP;
|
|
||||||
|
|
||||||
public enum eCDLog_AddrType
|
|
||||||
{
|
|
||||||
CARTROM, CARTRAM, WRAM, APURAM,
|
|
||||||
SGB_CARTROM, SGB_CARTRAM, SGB_WRAM, SGB_HRAM,
|
|
||||||
NUM
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum eTRACE : uint
|
|
||||||
{
|
|
||||||
CPU = 0,
|
|
||||||
SMP = 1,
|
|
||||||
GB = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum eCDLog_Flags
|
|
||||||
{
|
|
||||||
ExecFirst = 0x01,
|
|
||||||
ExecOperand = 0x02,
|
|
||||||
CPUData = 0x04,
|
|
||||||
DMAData = 0x08, //not supported yet
|
|
||||||
BRR = 0x80,
|
|
||||||
}
|
|
||||||
|
|
||||||
private snes_video_refresh_t video_refresh;
|
|
||||||
private snes_input_poll_t input_poll;
|
|
||||||
private snes_input_state_t input_state;
|
|
||||||
private snes_input_notify_t input_notify;
|
|
||||||
private snes_audio_sample_t audio_sample;
|
|
||||||
private snes_scanlineStart_t scanlineStart;
|
|
||||||
private snes_path_request_t pathRequest;
|
|
||||||
private snes_trace_t traceCallback;
|
|
||||||
|
|
||||||
public void QUERY_set_video_refresh(snes_video_refresh_t video_refresh) { this.video_refresh = video_refresh; }
|
|
||||||
// not used??
|
|
||||||
public void QUERY_set_input_poll(snes_input_poll_t input_poll) { this.input_poll = input_poll; }
|
|
||||||
public void QUERY_set_input_state(snes_input_state_t input_state) { this.input_state = input_state; }
|
|
||||||
public void QUERY_set_input_notify(snes_input_notify_t input_notify) { this.input_notify = input_notify; }
|
|
||||||
public void QUERY_set_path_request(snes_path_request_t pathRequest) { this.pathRequest = pathRequest; }
|
|
||||||
|
|
||||||
public delegate void snes_video_refresh_t(int* data, int width, int height);
|
|
||||||
public delegate void snes_input_poll_t();
|
|
||||||
public delegate short snes_input_state_t(int port, int device, int index, int id);
|
|
||||||
public delegate void snes_input_notify_t(int index);
|
|
||||||
public delegate void snes_audio_sample_t(short left, short right);
|
|
||||||
public delegate void snes_scanlineStart_t(int line);
|
|
||||||
public delegate string snes_path_request_t(int slot, string hint);
|
|
||||||
public delegate void snes_trace_t(uint which, string msg);
|
|
||||||
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
||||||
public struct CPURegs
|
|
||||||
{
|
|
||||||
public uint pc;
|
|
||||||
public ushort a, x, y, s, d, vector; //7x
|
|
||||||
public byte p, db, nothing, nothing2;
|
|
||||||
public ushort v, h;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct LayerEnables
|
|
||||||
{
|
|
||||||
private byte _BG1_Prio0, _BG1_Prio1;
|
|
||||||
private byte _BG2_Prio0, _BG2_Prio1;
|
|
||||||
private byte _BG3_Prio0, _BG3_Prio1;
|
|
||||||
private byte _BG4_Prio0, _BG4_Prio1;
|
|
||||||
private byte _Obj_Prio0, _Obj_Prio1, _Obj_Prio2, _Obj_Prio3;
|
|
||||||
|
|
||||||
public bool BG1_Prio0
|
|
||||||
{
|
|
||||||
get => _BG1_Prio0 != 0;
|
|
||||||
set => _BG1_Prio0 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool BG1_Prio1
|
|
||||||
{
|
|
||||||
get => _BG1_Prio1 != 0;
|
|
||||||
set => _BG1_Prio1 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool BG2_Prio0
|
|
||||||
{
|
|
||||||
get => _BG2_Prio0 != 0;
|
|
||||||
set => _BG2_Prio0 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool BG2_Prio1
|
|
||||||
{
|
|
||||||
get => _BG2_Prio1 != 0;
|
|
||||||
set => _BG2_Prio1 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool BG3_Prio0
|
|
||||||
{
|
|
||||||
get => _BG3_Prio0 != 0;
|
|
||||||
set => _BG3_Prio0 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool BG3_Prio1
|
|
||||||
{
|
|
||||||
get => _BG3_Prio1 != 0;
|
|
||||||
set => _BG3_Prio1 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool BG4_Prio0
|
|
||||||
{
|
|
||||||
get => _BG4_Prio0 != 0;
|
|
||||||
set => _BG4_Prio0 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool BG4_Prio1
|
|
||||||
{
|
|
||||||
get => _BG4_Prio1 != 0;
|
|
||||||
set => _BG4_Prio1 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Obj_Prio0
|
|
||||||
{
|
|
||||||
get => _Obj_Prio0 != 0;
|
|
||||||
set => _Obj_Prio0 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool Obj_Prio1
|
|
||||||
{
|
|
||||||
get => _Obj_Prio1 != 0;
|
|
||||||
set => _Obj_Prio1 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool Obj_Prio2
|
|
||||||
{
|
|
||||||
get => _Obj_Prio2 != 0;
|
|
||||||
set => _Obj_Prio2 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
public bool Obj_Prio3
|
|
||||||
{
|
|
||||||
get => _Obj_Prio3 != 0;
|
|
||||||
set => _Obj_Prio3 = (byte)(value ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
|
||||||
private struct CommStruct
|
|
||||||
{
|
|
||||||
[FieldOffset(0)]
|
|
||||||
//the cmd being executed
|
|
||||||
public readonly eMessage cmd;
|
|
||||||
[FieldOffset(4)]
|
|
||||||
//the status of the core
|
|
||||||
public readonly eStatus status;
|
|
||||||
[FieldOffset(8)]
|
|
||||||
//the SIG or BRK that the core is halted in
|
|
||||||
public readonly eMessage reason;
|
|
||||||
|
|
||||||
//flexible in/out parameters
|
|
||||||
//these are all "overloaded" a little so it isn't clear what's used for what in for any particular message..
|
|
||||||
//but I think it will beat having to have some kind of extremely verbose custom layouts for every message
|
|
||||||
[FieldOffset(16)]
|
|
||||||
public sbyte* str;
|
|
||||||
[FieldOffset(24)]
|
|
||||||
public void* ptr;
|
|
||||||
[FieldOffset(32)]
|
|
||||||
public uint id;
|
|
||||||
[FieldOffset(36)]
|
|
||||||
public uint addr;
|
|
||||||
[FieldOffset(40)]
|
|
||||||
public uint value;
|
|
||||||
[FieldOffset(44)]
|
|
||||||
public uint size;
|
|
||||||
[FieldOffset(48)]
|
|
||||||
public int port;
|
|
||||||
[FieldOffset(52)]
|
|
||||||
public int device;
|
|
||||||
[FieldOffset(56)]
|
|
||||||
public int index;
|
|
||||||
[FieldOffset(60)]
|
|
||||||
public int slot;
|
|
||||||
[FieldOffset(64)]
|
|
||||||
public int width;
|
|
||||||
[FieldOffset(68)]
|
|
||||||
public int height;
|
|
||||||
[FieldOffset(72)]
|
|
||||||
public int scanline;
|
|
||||||
[FieldOffset(76)]
|
|
||||||
public fixed int inports[2];
|
|
||||||
|
|
||||||
[FieldOffset(88)]
|
|
||||||
//this should always be used in pairs
|
|
||||||
public fixed long buf[3]; //ACTUALLY A POINTER but can't marshal it :(
|
|
||||||
[FieldOffset(112)]
|
|
||||||
public fixed int buf_size[3];
|
|
||||||
|
|
||||||
[FieldOffset(128)]
|
|
||||||
//bleck. this is a long so that it can be a 32/64bit pointer
|
|
||||||
public fixed long cdl_ptr[16];
|
|
||||||
[FieldOffset(256)]
|
|
||||||
public fixed int cdl_size[16];
|
|
||||||
|
|
||||||
[FieldOffset(320)]
|
|
||||||
public CPURegs cpuregs;
|
|
||||||
[FieldOffset(344)]
|
|
||||||
public LayerEnables layerEnables;
|
|
||||||
|
|
||||||
[FieldOffset(356)]
|
|
||||||
//static configuration-type information which can be grabbed off the core at any time without even needing a QUERY command
|
|
||||||
public SNES_REGION region;
|
|
||||||
[FieldOffset(360)]
|
|
||||||
public SNES_MAPPER mapper;
|
|
||||||
|
|
||||||
[FieldOffset(364)] private uint BLANK0;
|
|
||||||
|
|
||||||
|
|
||||||
//utilities
|
|
||||||
//TODO: make internal, wrap on the API instead of the comm
|
|
||||||
public string GetAscii() => _getAscii(str);
|
|
||||||
public bool GetBool() { return value != 0; }
|
|
||||||
|
|
||||||
private string _getAscii(sbyte* ptr)
|
|
||||||
{
|
|
||||||
int len = 0;
|
|
||||||
sbyte* junko = ptr;
|
|
||||||
while (junko[len] != 0) len++;
|
|
||||||
|
|
||||||
return new string(str, 0, len, System.Text.Encoding.ASCII);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SNES_REGION Region
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
return _comm->region;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public SNES_MAPPER Mapper
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
return _comm->mapper;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetLayerEnables(ref LayerEnables enables)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->layerEnables = enables;
|
|
||||||
QUERY_set_layer_enable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInputPortBeforeInit(int port, SNES_INPUT_PORT type)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->inports[port] = (int)type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Seal()
|
|
||||||
{
|
|
||||||
/* Cothreads can very easily acquire "pointer poison"; because their stack and even registers
|
|
||||||
* are part of state, any poisoned pointer that's used even temporarily might be persisted longer
|
|
||||||
* than needed. Most of the libsnes core cothreads handle internal matters only and aren't very
|
|
||||||
* vulnerable to pointer poison, but the main boss cothread is used heavily during init, when
|
|
||||||
* many syscalls happen and many kinds of poison can end up on the stack. so here, we call
|
|
||||||
* _core.DllInit() again, which recreates that cothread, zeroing out all of the memory first,
|
|
||||||
* as well as zeroing out the comm struct. */
|
|
||||||
_core.DllInit();
|
|
||||||
_exe.Seal();
|
|
||||||
_sealed = true;
|
|
||||||
foreach (var s in _readonlyFiles)
|
|
||||||
{
|
|
||||||
_exe.RemoveReadonlyFile(s);
|
|
||||||
}
|
|
||||||
_readonlyFiles.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AvoidRewind => false;
|
|
||||||
|
|
||||||
public void SaveStateBinary(BinaryWriter writer)
|
|
||||||
{
|
|
||||||
_exe.SaveStateBinary(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadStateBinary(BinaryReader reader)
|
|
||||||
{
|
|
||||||
_exe.LoadStateBinary(reader);
|
|
||||||
_core.PostLoadState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MemoryDomain GetPagesDomain()
|
|
||||||
{
|
|
||||||
return _exe.GetPagesDomain();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
using BizHawk.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
unsafe partial class LibsnesApi
|
|
||||||
{
|
|
||||||
private bool Handle_BRK(eMessage msg)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
switch (msg)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case eMessage.eMessage_BRK_hook_exec:
|
|
||||||
ExecHook(_comm->addr);
|
|
||||||
break;
|
|
||||||
case eMessage.eMessage_BRK_hook_read:
|
|
||||||
ReadHook(_comm->addr);
|
|
||||||
break;
|
|
||||||
case eMessage.eMessage_BRK_hook_write:
|
|
||||||
WriteHook(_comm->addr, (byte)_comm->value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case eMessage.eMessage_BRK_hook_exec_smp:
|
|
||||||
ExecHook_SMP(_comm->addr);
|
|
||||||
break;
|
|
||||||
case eMessage.eMessage_BRK_hook_read_smp:
|
|
||||||
ReadHook_SMP(_comm->addr);
|
|
||||||
break;
|
|
||||||
case eMessage.eMessage_BRK_hook_write_smp:
|
|
||||||
WriteHook_SMP(_comm->addr, (byte)_comm->value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//not supported yet
|
|
||||||
case eMessage.eMessage_BRK_hook_nmi:
|
|
||||||
break;
|
|
||||||
case eMessage.eMessage_BRK_hook_irq:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case eMessage.eMessage_BRK_scanlineStart:
|
|
||||||
scanlineStart?.Invoke(_comm->scanline);
|
|
||||||
break;
|
|
||||||
|
|
||||||
} //switch(msg)
|
|
||||||
|
|
||||||
_core.Message(eMessage.eMessage_Resume);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
using BizHawk.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
unsafe partial class LibsnesApi
|
|
||||||
{
|
|
||||||
private void WaitForCMD()
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (_comm->status == eStatus.eStatus_Idle)
|
|
||||||
break;
|
|
||||||
if (Handle_SIG(_comm->reason)) continue;
|
|
||||||
if (Handle_BRK(_comm->reason)) continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CMD_init(bool randomize)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->value = randomize ? 1u : 0u;
|
|
||||||
_core.Message(eMessage.eMessage_CMD_init);
|
|
||||||
WaitForCMD();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void CMD_power()
|
|
||||||
{
|
|
||||||
_core.Message(eMessage.eMessage_CMD_power);
|
|
||||||
WaitForCMD();
|
|
||||||
}
|
|
||||||
public void CMD_reset()
|
|
||||||
{
|
|
||||||
_core.Message(eMessage.eMessage_CMD_reset);
|
|
||||||
WaitForCMD();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CMD_run()
|
|
||||||
{
|
|
||||||
_core.Message(eMessage.eMessage_CMD_run);
|
|
||||||
WaitForCMD();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CMD_load_cartridge_super_game_boy(string rom_xml, byte[] rom_data, uint rom_size, byte[] dmg_data)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
SetAscii(0, rom_xml ?? "", () =>
|
|
||||||
SetBytes(1, rom_data, () =>
|
|
||||||
SetBytes(2, dmg_data, () =>
|
|
||||||
{
|
|
||||||
_core.Message(eMessage.eMessage_CMD_load_cartridge_sgb);
|
|
||||||
WaitForCMD();
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return _comm->GetBool();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CMD_load_cartridge_normal(byte[] rom_xml, byte[] rom_data)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
//why don't we need this for the other loads? I don't know, our XML handling is really confusing
|
|
||||||
string xml = rom_xml == null ? null : System.Text.Encoding.ASCII.GetString(rom_xml);
|
|
||||||
|
|
||||||
SetAscii(0, xml ?? "", () =>
|
|
||||||
SetBytes(1, rom_data, () =>
|
|
||||||
{
|
|
||||||
_core.Message(eMessage.eMessage_CMD_load_cartridge_normal);
|
|
||||||
WaitForCMD();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return _comm->GetBool();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,251 +0,0 @@
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesApi
|
|
||||||
{
|
|
||||||
public enum eMessage : int
|
|
||||||
{
|
|
||||||
eMessage_NotSet,
|
|
||||||
|
|
||||||
eMessage_Resume,
|
|
||||||
|
|
||||||
eMessage_QUERY_FIRST,
|
|
||||||
eMessage_QUERY_get_memory_size,
|
|
||||||
eMessage_QUERY_peek,
|
|
||||||
eMessage_QUERY_poke,
|
|
||||||
eMessage_QUERY_serialize_size,
|
|
||||||
eMessage_QUERY_set_color_lut,
|
|
||||||
eMessage_QUERY_GetMemoryIdName,
|
|
||||||
eMessage_QUERY_state_hook_exec,
|
|
||||||
eMessage_QUERY_state_hook_read,
|
|
||||||
eMessage_QUERY_state_hook_write,
|
|
||||||
eMessage_QUERY_state_hook_nmi,
|
|
||||||
eMessage_QUERY_state_hook_irq,
|
|
||||||
eMessage_QUERY_state_hook_exec_smp,
|
|
||||||
eMessage_QUERY_state_hook_read_smp,
|
|
||||||
eMessage_QUERY_state_hook_write_smp,
|
|
||||||
eMessage_QUERY_enable_trace,
|
|
||||||
eMessage_QUERY_enable_scanline,
|
|
||||||
eMessage_QUERY_enable_audio,
|
|
||||||
eMessage_QUERY_set_layer_enable,
|
|
||||||
eMessage_QUERY_set_backdropColor,
|
|
||||||
eMessage_QUERY_peek_logical_register,
|
|
||||||
eMessage_QUERY_peek_cpu_regs,
|
|
||||||
eMessage_QUERY_set_cdl,
|
|
||||||
eMessage_QUERY_LAST,
|
|
||||||
|
|
||||||
eMessage_CMD_FIRST,
|
|
||||||
eMessage_CMD_init,
|
|
||||||
eMessage_CMD_power,
|
|
||||||
eMessage_CMD_reset,
|
|
||||||
eMessage_CMD_run,
|
|
||||||
eMessage_CMD_serialize,
|
|
||||||
eMessage_CMD_unserialize,
|
|
||||||
eMessage_CMD_load_cartridge_normal,
|
|
||||||
eMessage_CMD_load_cartridge_sgb,
|
|
||||||
eMessage_CMD_term,
|
|
||||||
eMessage_CMD_unload_cartridge,
|
|
||||||
eMessage_CMD_LAST,
|
|
||||||
|
|
||||||
eMessage_SIG_video_refresh,
|
|
||||||
eMessage_SIG_input_poll,
|
|
||||||
eMessage_SIG_input_state,
|
|
||||||
eMessage_SIG_input_notify,
|
|
||||||
eMessage_SIG_audio_flush,
|
|
||||||
eMessage_SIG_path_request,
|
|
||||||
eMessage_SIG_trace_callback,
|
|
||||||
eMessage_SIG_allocSharedMemory, //?
|
|
||||||
eMessage_SIG_freeSharedMemory, //?
|
|
||||||
|
|
||||||
eMessage_BRK_Complete,
|
|
||||||
eMessage_BRK_hook_exec,
|
|
||||||
eMessage_BRK_hook_read,
|
|
||||||
eMessage_BRK_hook_write,
|
|
||||||
eMessage_BRK_hook_nmi,
|
|
||||||
eMessage_BRK_hook_irq,
|
|
||||||
eMessage_BRK_hook_exec_smp,
|
|
||||||
eMessage_BRK_hook_read_smp,
|
|
||||||
eMessage_BRK_hook_write_smp,
|
|
||||||
eMessage_BRK_scanlineStart,
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum eStatus : int
|
|
||||||
{
|
|
||||||
eStatus_Idle,
|
|
||||||
eStatus_CMD,
|
|
||||||
eStatus_BRK
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SNES_INPUT_PORT : int
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Joypad,
|
|
||||||
Multitap,
|
|
||||||
Mouse,
|
|
||||||
SuperScope,
|
|
||||||
Justifier,
|
|
||||||
Justifiers,
|
|
||||||
USART
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SNES_REG : int
|
|
||||||
{
|
|
||||||
//$2105
|
|
||||||
BG_MODE = 0,
|
|
||||||
BG3_PRIORITY = 1,
|
|
||||||
BG1_TILESIZE = 2,
|
|
||||||
BG2_TILESIZE = 3,
|
|
||||||
BG3_TILESIZE = 4,
|
|
||||||
BG4_TILESIZE = 5,
|
|
||||||
//$2107
|
|
||||||
BG1_SCADDR = 10,
|
|
||||||
BG1_SCSIZE = 11,
|
|
||||||
//$2108
|
|
||||||
BG2_SCADDR = 12,
|
|
||||||
BG2_SCSIZE = 13,
|
|
||||||
//$2109
|
|
||||||
BG3_SCADDR = 14,
|
|
||||||
BG3_SCSIZE = 15,
|
|
||||||
//$210A
|
|
||||||
BG4_SCADDR = 16,
|
|
||||||
BG4_SCSIZE = 17,
|
|
||||||
//$210B
|
|
||||||
BG1_TDADDR = 20,
|
|
||||||
BG2_TDADDR = 21,
|
|
||||||
//$210C
|
|
||||||
BG3_TDADDR = 22,
|
|
||||||
BG4_TDADDR = 23,
|
|
||||||
//$2133 SETINI
|
|
||||||
SETINI_MODE7_EXTBG = 30,
|
|
||||||
SETINI_HIRES = 31,
|
|
||||||
SETINI_OVERSCAN = 32,
|
|
||||||
SETINI_OBJ_INTERLACE = 33,
|
|
||||||
SETINI_SCREEN_INTERLACE = 34,
|
|
||||||
//$2130 CGWSEL
|
|
||||||
CGWSEL_COLORMASK = 40,
|
|
||||||
CGWSEL_COLORSUBMASK = 41,
|
|
||||||
CGWSEL_ADDSUBMODE = 42,
|
|
||||||
CGWSEL_DIRECTCOLOR = 43,
|
|
||||||
//$2101 OBSEL
|
|
||||||
OBSEL_NAMEBASE = 50,
|
|
||||||
OBSEL_NAMESEL = 51,
|
|
||||||
OBSEL_SIZE = 52,
|
|
||||||
//$2131 CGADSUB
|
|
||||||
CGADSUB_MODE = 60,
|
|
||||||
CGADSUB_HALF = 61,
|
|
||||||
CGADSUB_BG4 = 62,
|
|
||||||
CGADSUB_BG3 = 63,
|
|
||||||
CGADSUB_BG2 = 64,
|
|
||||||
CGADSUB_BG1 = 65,
|
|
||||||
CGADSUB_OBJ = 66,
|
|
||||||
CGADSUB_BACKDROP = 67,
|
|
||||||
//$212C TM
|
|
||||||
TM_BG1 = 70,
|
|
||||||
TM_BG2 = 71,
|
|
||||||
TM_BG3 = 72,
|
|
||||||
TM_BG4 = 73,
|
|
||||||
TM_OBJ = 74,
|
|
||||||
//$212D TM
|
|
||||||
TS_BG1 = 80,
|
|
||||||
TS_BG2 = 81,
|
|
||||||
TS_BG3 = 82,
|
|
||||||
TS_BG4 = 83,
|
|
||||||
TS_OBJ = 84,
|
|
||||||
//Mode7 regs
|
|
||||||
M7SEL_REPEAT = 90,
|
|
||||||
M7SEL_HFLIP = 91,
|
|
||||||
M7SEL_VFLIP = 92,
|
|
||||||
M7A = 93,
|
|
||||||
M7B = 94,
|
|
||||||
M7C = 95,
|
|
||||||
M7D = 96,
|
|
||||||
M7X = 97,
|
|
||||||
M7Y = 98,
|
|
||||||
//BG scroll regs
|
|
||||||
BG1HOFS = 100,
|
|
||||||
BG1VOFS = 101,
|
|
||||||
BG2HOFS = 102,
|
|
||||||
BG2VOFS = 103,
|
|
||||||
BG3HOFS = 104,
|
|
||||||
BG3VOFS = 105,
|
|
||||||
BG4HOFS = 106,
|
|
||||||
BG4VOFS = 107,
|
|
||||||
M7HOFS = 108,
|
|
||||||
M7VOFS = 109,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SNES_MEMORY : uint
|
|
||||||
{
|
|
||||||
CARTRIDGE_RAM = 0,
|
|
||||||
CARTRIDGE_RTC = 1,
|
|
||||||
BSX_RAM = 2,
|
|
||||||
BSX_PRAM = 3,
|
|
||||||
SUFAMI_TURBO_A_RAM = 4,
|
|
||||||
SUFAMI_TURBO_B_RAM = 5,
|
|
||||||
SGB_CARTRAM = 6,
|
|
||||||
SGB_RTC = 7,
|
|
||||||
SGB_WRAM = 8,
|
|
||||||
SGB_HRAM = 9,
|
|
||||||
SA1_IRAM = 10,
|
|
||||||
|
|
||||||
WRAM = 100,
|
|
||||||
APURAM = 101,
|
|
||||||
VRAM = 102,
|
|
||||||
OAM = 103,
|
|
||||||
CGRAM = 104,
|
|
||||||
|
|
||||||
CARTRIDGE_ROM = 105,
|
|
||||||
|
|
||||||
SYSBUS = 200,
|
|
||||||
LOGICAL_REGS = 201
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SNES_MAPPER : byte
|
|
||||||
{
|
|
||||||
LOROM = 0,
|
|
||||||
HIROM = 1,
|
|
||||||
EXLOROM = 2,
|
|
||||||
EXHIROM = 3,
|
|
||||||
SUPERFXROM = 4,
|
|
||||||
SA1ROM = 5,
|
|
||||||
SPC7110ROM = 6,
|
|
||||||
BSCLOROM = 7,
|
|
||||||
BSCHIROM = 8,
|
|
||||||
BSXROM = 9,
|
|
||||||
STROM = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SNES_REGION : uint
|
|
||||||
{
|
|
||||||
NTSC = 0,
|
|
||||||
PAL = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SNES_DEVICE : uint
|
|
||||||
{
|
|
||||||
NONE = 0,
|
|
||||||
JOYPAD = 1,
|
|
||||||
MULTITAP = 2,
|
|
||||||
MOUSE = 3,
|
|
||||||
SUPER_SCOPE = 4,
|
|
||||||
JUSTIFIER = 5,
|
|
||||||
JUSTIFIERS = 6,
|
|
||||||
SERIAL_CABLE = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SNES_DEVICE_ID : uint
|
|
||||||
{
|
|
||||||
JOYPAD_B = 0,
|
|
||||||
JOYPAD_Y = 1,
|
|
||||||
JOYPAD_SELECT = 2,
|
|
||||||
JOYPAD_START = 3,
|
|
||||||
JOYPAD_UP = 4,
|
|
||||||
JOYPAD_DOWN = 5,
|
|
||||||
JOYPAD_LEFT = 6,
|
|
||||||
JOYPAD_RIGHT = 7,
|
|
||||||
JOYPAD_A = 8,
|
|
||||||
JOYPAD_X = 9,
|
|
||||||
JOYPAD_L = 10,
|
|
||||||
JOYPAD_R = 11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,225 +0,0 @@
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
unsafe partial class LibsnesApi
|
|
||||||
{
|
|
||||||
public int QUERY_get_memory_size(SNES_MEMORY id)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->value = (uint)id;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_get_memory_size);
|
|
||||||
return (int)_comm->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string QUERY_MemoryNameForId(SNES_MEMORY id)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->id = (uint)id;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_GetMemoryIdName);
|
|
||||||
return _comm->GetAscii();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte* QUERY_get_memory_data(SNES_MEMORY id)
|
|
||||||
{
|
|
||||||
string name = QUERY_MemoryNameForId(id);
|
|
||||||
_ = _sharedMemoryBlocks.TryGetValue(name, out var ret);
|
|
||||||
return (byte*)ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte QUERY_peek(SNES_MEMORY id, uint addr)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->id = (uint)id;
|
|
||||||
_comm->addr = addr;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_peek);
|
|
||||||
return (byte)_comm->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void QUERY_poke(SNES_MEMORY id, uint addr, byte val)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->id = (uint)id;
|
|
||||||
_comm->addr = addr;
|
|
||||||
_comm->value = val;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_poke);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_color_lut(IntPtr colors)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->ptr = colors.ToPointer();
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_set_color_lut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_state_hook_exec(bool state)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->value = state ? 1u : 0u;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_state_hook_exec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_state_hook_read(bool state)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->value = state ? 1u : 0u;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_state_hook_read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_state_hook_write(bool state)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->value = state ? 1u : 0u;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_state_hook_write);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_trace_callback(int mask, snes_trace_t callback)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
this.traceCallback = callback;
|
|
||||||
_comm->value = (uint)mask;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_enable_trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void QUERY_set_scanlineStart(snes_scanlineStart_t scanlineStart)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
this.scanlineStart = scanlineStart;
|
|
||||||
_comm->value = (scanlineStart != null) ? 1u : 0u;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_enable_scanline);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void QUERY_set_audio_sample(snes_audio_sample_t audio_sample)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
this.audio_sample = audio_sample;
|
|
||||||
_comm->value = (audio_sample != null) ? 1u : 0u;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_enable_audio);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_layer_enable()
|
|
||||||
{
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_set_layer_enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_backdropColor(int backdropColor)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->value = (uint)backdropColor;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_set_backdropColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int QUERY_peek_logical_register(SNES_REG reg)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_comm->id = (uint)reg;
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_peek_logical_register);
|
|
||||||
return (int)_comm->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_peek_cpu_regs(out CPURegs ret)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_peek_cpu_regs);
|
|
||||||
ret = _comm->cpuregs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QUERY_set_cdl(ICodeDataLog cdl)
|
|
||||||
{
|
|
||||||
if (_exe == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
_comm->cdl_ptr[i] = 0;
|
|
||||||
_comm->cdl_size[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdl != null)
|
|
||||||
{
|
|
||||||
int zz = 0;
|
|
||||||
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("CARTROM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["CARTROM"].Length;
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("CARTROM-DB").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["CARTROM"].Length;
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("CARTROM-D").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["CARTROM"].Length * 2;
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
if (cdl.Has("CARTRAM"))
|
|
||||||
{
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("CARTRAM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["CARTRAM"].Length;
|
|
||||||
}
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("WRAM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["WRAM"].Length;
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("APURAM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["APURAM"].Length;
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
if (cdl.Has("SGB_CARTROM"))
|
|
||||||
{
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("SGB_CARTROM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["SGB_CARTROM"].Length;
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
if (cdl.Has("SGB_CARTRAM"))
|
|
||||||
{
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("SGB_CARTRAM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["SGB_CARTRAM"].Length;
|
|
||||||
}
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("SGB_WRAM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["SGB_WRAM"].Length;
|
|
||||||
zz++;
|
|
||||||
|
|
||||||
_comm->cdl_ptr[zz] = cdl.GetPin("SGB_HRAM").ToInt64();
|
|
||||||
_comm->cdl_size[zz] = cdl["SGB_HRAM"].Length;
|
|
||||||
zz++;
|
|
||||||
}
|
|
||||||
else zz += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
_core.Message(eMessage.eMessage_QUERY_set_cdl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
using BizHawk.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
unsafe partial class LibsnesApi
|
|
||||||
{
|
|
||||||
private bool Handle_SIG(eMessage msg)
|
|
||||||
{
|
|
||||||
using (_exe.EnterExit())
|
|
||||||
{
|
|
||||||
switch (msg)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case eMessage.eMessage_SIG_video_refresh:
|
|
||||||
{
|
|
||||||
int width = _comm->width;
|
|
||||||
int height = _comm->height;
|
|
||||||
video_refresh?.Invoke((int*)_comm->ptr, width, height);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eMessage.eMessage_SIG_input_poll:
|
|
||||||
break;
|
|
||||||
case eMessage.eMessage_SIG_input_state:
|
|
||||||
{
|
|
||||||
int port = _comm->port;
|
|
||||||
int device = _comm->device;
|
|
||||||
int index = _comm->index;
|
|
||||||
int id = (int)_comm->id;
|
|
||||||
if (input_state != null)
|
|
||||||
_comm->value = (uint)input_state(port, device, index, id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eMessage.eMessage_SIG_input_notify:
|
|
||||||
{
|
|
||||||
input_notify?.Invoke(_comm->index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eMessage.eMessage_SIG_audio_flush:
|
|
||||||
{
|
|
||||||
uint nsamples = _comm->size;
|
|
||||||
|
|
||||||
if (audio_sample != null)
|
|
||||||
{
|
|
||||||
var audiobuffer = (short*)_comm->ptr;
|
|
||||||
for (uint i = 0; i < nsamples;)
|
|
||||||
{
|
|
||||||
var left = audiobuffer[i++];
|
|
||||||
var right = audiobuffer[i++];
|
|
||||||
audio_sample(left, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eMessage.eMessage_SIG_path_request:
|
|
||||||
{
|
|
||||||
int slot = _comm->slot;
|
|
||||||
string hint = _comm->GetAscii();
|
|
||||||
string ret = hint;
|
|
||||||
if (pathRequest != null)
|
|
||||||
hint = pathRequest(slot, hint);
|
|
||||||
CopyAscii(0, hint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eMessage.eMessage_SIG_trace_callback:
|
|
||||||
{
|
|
||||||
traceCallback?.Invoke(_comm->value, _comm->GetAscii());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eMessage.eMessage_SIG_allocSharedMemory:
|
|
||||||
{
|
|
||||||
// NB: shared memory blocks are allocated on the unmanaged side
|
|
||||||
var name = _comm->GetAscii();
|
|
||||||
var size = _comm->size;
|
|
||||||
var ptr = _comm->ptr;
|
|
||||||
|
|
||||||
if (_sharedMemoryBlocks.ContainsKey(name))
|
|
||||||
throw new InvalidOperationException("Re-defined a shared memory block. Check bsnes init/shutdown code. Block name: " + name);
|
|
||||||
|
|
||||||
_sharedMemoryBlocks.Add(name, (IntPtr)ptr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case eMessage.eMessage_SIG_freeSharedMemory:
|
|
||||||
throw new InvalidOperationException("Unexpected call: SIG_freeSharedMemory");
|
|
||||||
} //switch(msg)
|
|
||||||
|
|
||||||
_core.Message(eMessage.eMessage_Resume);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +1,8 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Common.NumberExtensions;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
{
|
{
|
||||||
public class LibsnesControllerDeck
|
|
||||||
{
|
|
||||||
public enum ControllerType
|
|
||||||
{
|
|
||||||
Unplugged,
|
|
||||||
Gamepad,
|
|
||||||
Multitap,
|
|
||||||
Mouse,
|
|
||||||
SuperScope,
|
|
||||||
Justifier,
|
|
||||||
Payload
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ILibsnesController Factory(ControllerType t, LibsnesCore.SnesSyncSettings ss)
|
|
||||||
{
|
|
||||||
switch (t)
|
|
||||||
{
|
|
||||||
case ControllerType.Unplugged:
|
|
||||||
return new SnesUnpluggedController();
|
|
||||||
case ControllerType.Gamepad:
|
|
||||||
return new SnesController();
|
|
||||||
case ControllerType.Multitap:
|
|
||||||
return new SnesMultitapController();
|
|
||||||
case ControllerType.Payload:
|
|
||||||
return new SnesPayloadController();
|
|
||||||
case ControllerType.Mouse:
|
|
||||||
return new SnesMouseController
|
|
||||||
{
|
|
||||||
LimitAnalogChangeSensitivity = ss.LimitAnalogChangeSensitivity
|
|
||||||
};
|
|
||||||
case ControllerType.SuperScope:
|
|
||||||
return new SnesSuperScopeController();
|
|
||||||
case ControllerType.Justifier:
|
|
||||||
return new SnesJustifierController();
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ILibsnesController[] _ports;
|
|
||||||
private readonly ControlDefUnMerger[] _mergers;
|
|
||||||
|
|
||||||
public ControllerDefinition Definition { get; }
|
|
||||||
|
|
||||||
public LibsnesControllerDeck(LibsnesCore.SnesSyncSettings ss)
|
|
||||||
{
|
|
||||||
_ports = new[]
|
|
||||||
{
|
|
||||||
Factory(ss.LeftPort, ss),
|
|
||||||
Factory(ss.RightPort, ss)
|
|
||||||
};
|
|
||||||
|
|
||||||
Definition = ControllerDefinitionMerger.GetMerged(
|
|
||||||
"SNES Controller",
|
|
||||||
_ports.Select(p => p.Definition),
|
|
||||||
out var tmp);
|
|
||||||
_mergers = tmp.ToArray();
|
|
||||||
|
|
||||||
// add buttons that the core itself will handle
|
|
||||||
Definition.BoolButtons.Add("Reset");
|
|
||||||
Definition.BoolButtons.Add("Power");
|
|
||||||
|
|
||||||
Definition.MakeImmutable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NativeInit(LibsnesApi api)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
api.SetInputPortBeforeInit(i, _ports[i].PortType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public short CoreInputState(IController controller, int port, int device, int index, int id)
|
|
||||||
{
|
|
||||||
return _ports[port].GetState(_mergers[port].UnMerge(controller), index, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class SNESControllerDefExtensions
|
internal static class SNESControllerDefExtensions
|
||||||
{
|
{
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
@ -97,296 +14,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
=> def.AddXYPair(nameFormat, AxisPairOrientation.RightAndDown, 0.RangeTo(255), 128, 0.RangeTo(239), 120); //TODO verify direction against hardware
|
=> def.AddXYPair(nameFormat, AxisPairOrientation.RightAndDown, 0.RangeTo(255), 128, 0.RangeTo(239), 120); //TODO verify direction against hardware
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ILibsnesController
|
public static class SnesMouseController
|
||||||
{
|
{
|
||||||
/// <summary>
|
public static readonly ControllerDefinition Definition
|
||||||
/// the type to pass back to the native init
|
|
||||||
/// </summary>
|
|
||||||
LibsnesApi.SNES_INPUT_PORT PortType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// respond to a native core poll
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="controller">controller input from user, remapped</param>
|
|
||||||
/// <param name="index">libsnes specific value, sometimes multitap number</param>
|
|
||||||
/// <param name="id">libsnes specific value, sometimes button number</param>
|
|
||||||
short GetState(IController controller, int index, int id);
|
|
||||||
|
|
||||||
ControllerDefinition Definition { get; }
|
|
||||||
|
|
||||||
// due to the way things are implemented, right now, all of the ILibsnesControllers are stateless
|
|
||||||
// but if one needed state, that would be doable
|
|
||||||
// void SyncState(Serializer ser);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesController : ILibsnesController
|
|
||||||
{
|
|
||||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.Joypad;
|
|
||||||
|
|
||||||
private static readonly string[] Buttons =
|
|
||||||
{
|
|
||||||
"0B",
|
|
||||||
"0Y",
|
|
||||||
"0Select",
|
|
||||||
"0Start",
|
|
||||||
"0Up",
|
|
||||||
"0Down",
|
|
||||||
"0Left",
|
|
||||||
"0Right",
|
|
||||||
"0A",
|
|
||||||
"0X",
|
|
||||||
"0L",
|
|
||||||
"0R"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int ButtonOrder(string btn)
|
|
||||||
{
|
|
||||||
var order = new Dictionary<string, int>
|
|
||||||
{
|
|
||||||
["0Up"] = 0,
|
|
||||||
["0Down"] = 1,
|
|
||||||
["0Left"] = 2,
|
|
||||||
["0Right"] = 3,
|
|
||||||
|
|
||||||
["0Select"] = 4,
|
|
||||||
["0Start"] = 5,
|
|
||||||
|
|
||||||
["0Y"] = 6,
|
|
||||||
["0B"] = 7,
|
|
||||||
|
|
||||||
["0X"] = 8,
|
|
||||||
["0A"] = 9,
|
|
||||||
|
|
||||||
["0L"] = 10,
|
|
||||||
["0R"] = 11
|
|
||||||
};
|
|
||||||
|
|
||||||
return order[btn];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly ControllerDefinition _definition = new("(SNES Controller fragment)")
|
|
||||||
{
|
|
||||||
BoolButtons = Buttons.OrderBy(ButtonOrder).ToList()
|
|
||||||
};
|
|
||||||
|
|
||||||
public ControllerDefinition Definition { get; } = _definition;
|
|
||||||
|
|
||||||
public short GetState(IController controller, int index, int id)
|
|
||||||
{
|
|
||||||
if (id >= 12)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (short)(controller.IsPressed(Buttons[id]) ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesMultitapController : ILibsnesController
|
|
||||||
{
|
|
||||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.Multitap;
|
|
||||||
|
|
||||||
private static readonly string[] Buttons =
|
|
||||||
{
|
|
||||||
"B",
|
|
||||||
"Y",
|
|
||||||
"Select",
|
|
||||||
"Start",
|
|
||||||
"Up",
|
|
||||||
"Down",
|
|
||||||
"Left",
|
|
||||||
"Right",
|
|
||||||
"A",
|
|
||||||
"X",
|
|
||||||
"L",
|
|
||||||
"R"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int ButtonOrder(string btn)
|
|
||||||
{
|
|
||||||
var order = new Dictionary<string, int>
|
|
||||||
{
|
|
||||||
["Up"] = 0,
|
|
||||||
["Down"] = 1,
|
|
||||||
["Left"] = 2,
|
|
||||||
["Right"] = 3,
|
|
||||||
|
|
||||||
["Select"] = 4,
|
|
||||||
["Start"] = 5,
|
|
||||||
|
|
||||||
["Y"] = 6,
|
|
||||||
["B"] = 7,
|
|
||||||
|
|
||||||
["X"] = 8,
|
|
||||||
["A"] = 9,
|
|
||||||
|
|
||||||
["L"] = 10,
|
|
||||||
["R"] = 11
|
|
||||||
};
|
|
||||||
|
|
||||||
return order[btn];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly ControllerDefinition _definition = new("(SNES Controller fragment)")
|
|
||||||
{
|
|
||||||
BoolButtons = Enumerable.Range(0, 4)
|
|
||||||
.SelectMany(i => Buttons
|
|
||||||
.OrderBy(ButtonOrder)
|
|
||||||
.Select(b => i + b))
|
|
||||||
.Concat(new[] { "0Toggle Multitap" })
|
|
||||||
.ToList()
|
|
||||||
};
|
|
||||||
|
|
||||||
public ControllerDefinition Definition { get; } = _definition;
|
|
||||||
|
|
||||||
public short GetState(IController controller, int index, int id)
|
|
||||||
{
|
|
||||||
if (id == 16)
|
|
||||||
{
|
|
||||||
return (short)(controller.IsPressed("0Toggle Multitap") ? 1 : 0);
|
|
||||||
}
|
|
||||||
if (id >= 12)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (short)(controller.IsPressed(index + Buttons[id]) ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesPayloadController : ILibsnesController
|
|
||||||
{
|
|
||||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.Multitap;
|
|
||||||
|
|
||||||
private static readonly ControllerDefinition _definition = new("(SNES Controller fragment)")
|
|
||||||
{
|
|
||||||
BoolButtons = Enumerable.Range(0, 32).Select(i => "0B" + i).ToList()
|
|
||||||
};
|
|
||||||
|
|
||||||
public ControllerDefinition Definition { get; } = _definition;
|
|
||||||
|
|
||||||
public short GetState(IController controller, int index, int id)
|
|
||||||
{
|
|
||||||
return (short)(controller.IsPressed("0B" + (index << 4 & 16 | id)) ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesUnpluggedController : ILibsnesController
|
|
||||||
{
|
|
||||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.None;
|
|
||||||
|
|
||||||
private static readonly ControllerDefinition _definition = new("(SNES Controller fragment)");
|
|
||||||
|
|
||||||
public ControllerDefinition Definition { get; } = _definition;
|
|
||||||
|
|
||||||
public short GetState(IController controller, int index, int id)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesMouseController : ILibsnesController
|
|
||||||
{
|
|
||||||
public LibsnesApi.SNES_INPUT_PORT PortType => LibsnesApi.SNES_INPUT_PORT.Mouse;
|
|
||||||
|
|
||||||
private static readonly ControllerDefinition _definition
|
|
||||||
= new ControllerDefinition("(SNES Controller fragment)") { BoolButtons = { "0Mouse Left", "0Mouse Right" } }
|
= new ControllerDefinition("(SNES Controller fragment)") { BoolButtons = { "0Mouse Left", "0Mouse Right" } }
|
||||||
.AddXYPair("0Mouse {0}", AxisPairOrientation.RightAndDown, (-127).RangeTo(127), 0); //TODO verify direction against hardware, R+D inferred from behaviour in Mario Paint
|
.AddXYPair("0Mouse {0}", AxisPairOrientation.RightAndDown, (-127).RangeTo(127), 0); //TODO verify direction against hardware, R+D inferred from behaviour in Mario Paint
|
||||||
|
|
||||||
public ControllerDefinition Definition => _definition;
|
|
||||||
|
|
||||||
public bool LimitAnalogChangeSensitivity { get; set; } = true;
|
|
||||||
|
|
||||||
public short GetState(IController controller, int index, int id)
|
|
||||||
{
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case 0:
|
|
||||||
var x = controller.AxisValue("0Mouse X");
|
|
||||||
if (LimitAnalogChangeSensitivity)
|
|
||||||
{
|
|
||||||
x = x.Clamp(-10, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (short)x;
|
|
||||||
case 1:
|
|
||||||
var y = controller.AxisValue("0Mouse Y");
|
|
||||||
if (LimitAnalogChangeSensitivity)
|
|
||||||
{
|
|
||||||
y = y.Clamp(-10, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (short)y;
|
|
||||||
case 2:
|
|
||||||
return (short)(controller.IsPressed("0Mouse Left") ? 1 : 0);
|
|
||||||
case 3:
|
|
||||||
return (short)(controller.IsPressed("0Mouse Right") ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesSuperScopeController : ILibsnesController
|
|
||||||
{
|
|
||||||
public LibsnesApi.SNES_INPUT_PORT PortType => LibsnesApi.SNES_INPUT_PORT.SuperScope;
|
|
||||||
|
|
||||||
private static readonly ControllerDefinition _definition
|
|
||||||
= new ControllerDefinition("(SNES Controller fragment)") { BoolButtons = { "0Trigger", "0Cursor", "0Turbo", "0Pause", "0Offscreen" } }
|
|
||||||
.AddLightGun("0Scope {0}");
|
|
||||||
|
|
||||||
public ControllerDefinition Definition => _definition;
|
|
||||||
|
|
||||||
public short GetState(IController controller, int index, int id)
|
|
||||||
{
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case 0:
|
|
||||||
if (controller.IsPressed("0Offscreen")) return -1;
|
|
||||||
return (short)controller.AxisValue("0Scope X");
|
|
||||||
case 1:
|
|
||||||
if (controller.IsPressed("0Offscreen")) return -1;
|
|
||||||
return (short)controller.AxisValue("0Scope Y");
|
|
||||||
case 2:
|
|
||||||
return (short)(controller.IsPressed("0Trigger") ? 1 : 0);
|
|
||||||
case 3:
|
|
||||||
return (short)(controller.IsPressed("0Cursor") ? 1 : 0);
|
|
||||||
case 4:
|
|
||||||
return (short)(controller.IsPressed("0Turbo") ? 1 : 0);
|
|
||||||
case 5:
|
|
||||||
return (short)(controller.IsPressed("0Pause") ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesJustifierController : ILibsnesController
|
|
||||||
{
|
|
||||||
public LibsnesApi.SNES_INPUT_PORT PortType => LibsnesApi.SNES_INPUT_PORT.Justifier;
|
|
||||||
|
|
||||||
private static readonly ControllerDefinition _definition
|
|
||||||
= new ControllerDefinition("(SNES Controller fragment)") { BoolButtons = { "0Trigger", "0Start", "0Offscreen", "1Trigger", "1Start", "1Offscreen" } }
|
|
||||||
.AddLightGun("0Justifier {0}")
|
|
||||||
.AddLightGun("1Justifier {0}");
|
|
||||||
|
|
||||||
public ControllerDefinition Definition => _definition;
|
|
||||||
|
|
||||||
public short GetState(IController controller, int index, int id)
|
|
||||||
{
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case 0:
|
|
||||||
if (controller.IsPressed(index + "Offscreen")) return -1;
|
|
||||||
return (short)controller.AxisValue(index + "Justifier X");
|
|
||||||
case 1:
|
|
||||||
if (controller.IsPressed(index + "Offscreen")) return -1;
|
|
||||||
return (short)controller.AxisValue(index + "Justifier Y");
|
|
||||||
case 2:
|
|
||||||
return (short)(controller.IsPressed(index + "Trigger") ? 1 : 0);
|
|
||||||
case 3:
|
|
||||||
return (short)(controller.IsPressed(index + "Start") ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : ICodeDataLogger
|
|
||||||
{
|
|
||||||
public void SetCDL(ICodeDataLog cdl)
|
|
||||||
{
|
|
||||||
_currCdl?.Unpin();
|
|
||||||
_currCdl = cdl;
|
|
||||||
_currCdl?.Pin();
|
|
||||||
|
|
||||||
// set it no matter what. if its null, the cdl will be unhooked from libsnes internally
|
|
||||||
Api.QUERY_set_cdl(_currCdl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NewCDL(ICodeDataLog cdl)
|
|
||||||
{
|
|
||||||
void AddIfExists(string name, string addAs = null)
|
|
||||||
{
|
|
||||||
var found = _memoryDomains[name];
|
|
||||||
if (found is not null) cdl[addAs ?? name] = new byte[found.Size];
|
|
||||||
}
|
|
||||||
|
|
||||||
cdl["CARTROM"] = new byte[_memoryDomains["CARTROM"]!.Size];
|
|
||||||
cdl["CARTROM-DB"] = new byte[_memoryDomains["CARTROM"]!.Size];
|
|
||||||
cdl["CARTROM-D"] = new byte[_memoryDomains["CARTROM"]!.Size*2];
|
|
||||||
cdl["WRAM"] = new byte[_memoryDomains["WRAM"]!.Size];
|
|
||||||
cdl["APURAM"] = new byte[_memoryDomains["APURAM"]!.Size];
|
|
||||||
AddIfExists("CARTRAM");
|
|
||||||
|
|
||||||
if (IsSGB)
|
|
||||||
{
|
|
||||||
cdl["SGB_CARTROM"] = new byte[_memoryDomains["SGB CARTROM"]!.Size];
|
|
||||||
cdl["SGB_HRAM"] = new byte[_memoryDomains["SGB HRAM"]!.Size];
|
|
||||||
cdl["SGB_WRAM"] = new byte[_memoryDomains["SGB WRAM"]!.Size];
|
|
||||||
AddIfExists("SGB CARTRAM", addAs: "SGB_CARTRAM");
|
|
||||||
}
|
|
||||||
|
|
||||||
cdl.SubType = "SNES";
|
|
||||||
cdl.SubVer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DisassembleCDL(Stream s, ICodeDataLog cdl)
|
|
||||||
{
|
|
||||||
// TODO: should this throw a NotImplementedException?
|
|
||||||
// not supported yet
|
|
||||||
}
|
|
||||||
|
|
||||||
private ICodeDataLog _currCdl;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : IDebuggable
|
|
||||||
{
|
|
||||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
|
||||||
{
|
|
||||||
Api.QUERY_peek_cpu_regs(out var regs);
|
|
||||||
|
|
||||||
bool fn = (regs.p & 0x80) != 0;
|
|
||||||
bool fv = (regs.p & 0x40) != 0;
|
|
||||||
bool fm = (regs.p & 0x20) != 0;
|
|
||||||
bool fx = (regs.p & 0x10) != 0;
|
|
||||||
bool fd = (regs.p & 0x08) != 0;
|
|
||||||
bool fi = (regs.p & 0x04) != 0;
|
|
||||||
bool fz = (regs.p & 0x02) != 0;
|
|
||||||
bool fc = (regs.p & 0x01) != 0;
|
|
||||||
|
|
||||||
return new Dictionary<string, RegisterValue>
|
|
||||||
{
|
|
||||||
["PC"] = regs.pc,
|
|
||||||
["A"] = regs.a,
|
|
||||||
["X"] = regs.x,
|
|
||||||
["Y"] = regs.y,
|
|
||||||
["S"] = regs.s,
|
|
||||||
["D"] = regs.d,
|
|
||||||
["Vector"] = regs.vector,
|
|
||||||
["P"] = regs.p,
|
|
||||||
["Flag N"] = fn,
|
|
||||||
["Flag V"] = fv,
|
|
||||||
["Flag M"] = fm,
|
|
||||||
["Flag X"] = fx,
|
|
||||||
["Flag D"] = fd,
|
|
||||||
["Flag I"] = fi,
|
|
||||||
["Flag Z"] = fz,
|
|
||||||
["Flag C"] = fc,
|
|
||||||
["V"] = regs.v,
|
|
||||||
["H"] = regs.h
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[FeatureNotImplemented]
|
|
||||||
public void SetCpuRegister(string register, int value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
|
|
||||||
|
|
||||||
public bool CanStep(StepType type)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[FeatureNotImplemented]
|
|
||||||
public void Step(StepType type)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
[FeatureNotImplemented]
|
|
||||||
public long TotalExecutedCycles => throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : IEmulator
|
|
||||||
{
|
|
||||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
|
||||||
|
|
||||||
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
|
|
||||||
|
|
||||||
public bool FrameAdvance(IController controller, bool render, bool renderSound)
|
|
||||||
{
|
|
||||||
_controller = controller;
|
|
||||||
|
|
||||||
/* if the input poll callback is called, it will set this to false
|
|
||||||
* this has to be done before we save the per-frame state in deterministic
|
|
||||||
* mode, because in there, the core actually advances, and might advance
|
|
||||||
* through the point in time where IsLagFrame gets set to false. makes sense?
|
|
||||||
*/
|
|
||||||
|
|
||||||
IsLagFrame = true;
|
|
||||||
|
|
||||||
if (_tracer.IsEnabled())
|
|
||||||
{
|
|
||||||
//Api.QUERY_set_trace_callback(1<<(int)LibsnesApi.eTRACE.SMP, _tracecb); //TEST -- it works but theres no way to control it from the frontend now
|
|
||||||
|
|
||||||
if(IsSGB)
|
|
||||||
Api.QUERY_set_trace_callback(1<<(int)LibsnesApi.eTRACE.GB, _tracecb);
|
|
||||||
else
|
|
||||||
Api.QUERY_set_trace_callback(1<<(int)LibsnesApi.eTRACE.CPU, _tracecb);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Api.QUERY_set_trace_callback(0,null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// speedup when sound rendering is not needed
|
|
||||||
Api.QUERY_set_audio_sample(renderSound ? _soundcb : null);
|
|
||||||
|
|
||||||
bool resetSignal = controller.IsPressed("Reset");
|
|
||||||
if (resetSignal)
|
|
||||||
{
|
|
||||||
Api.CMD_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool powerSignal = controller.IsPressed("Power");
|
|
||||||
if (powerSignal)
|
|
||||||
{
|
|
||||||
Api.CMD_power();
|
|
||||||
}
|
|
||||||
|
|
||||||
var enables = new LibsnesApi.LayerEnables
|
|
||||||
{
|
|
||||||
BG1_Prio0 = _settings.ShowBG1_0,
|
|
||||||
BG1_Prio1 = _settings.ShowBG1_1,
|
|
||||||
BG2_Prio0 = _settings.ShowBG2_0,
|
|
||||||
BG2_Prio1 = _settings.ShowBG2_1,
|
|
||||||
BG3_Prio0 = _settings.ShowBG3_0,
|
|
||||||
BG3_Prio1 = _settings.ShowBG3_1,
|
|
||||||
BG4_Prio0 = _settings.ShowBG4_0,
|
|
||||||
BG4_Prio1 = _settings.ShowBG4_1,
|
|
||||||
Obj_Prio0 = _settings.ShowOBJ_0,
|
|
||||||
Obj_Prio1 = _settings.ShowOBJ_1,
|
|
||||||
Obj_Prio2 = _settings.ShowOBJ_2,
|
|
||||||
Obj_Prio3 = _settings.ShowOBJ_3
|
|
||||||
};
|
|
||||||
|
|
||||||
Api.SetLayerEnables(ref enables);
|
|
||||||
|
|
||||||
RefreshMemoryCallbacks(false);
|
|
||||||
|
|
||||||
// apparently this is one frame?
|
|
||||||
Api.CMD_run();
|
|
||||||
_timeFrameCounter++;
|
|
||||||
|
|
||||||
// once upon a time we forwarded messages from bsnes here, by checking for queued text messages, but I don't think it's needed any longer
|
|
||||||
if (IsLagFrame)
|
|
||||||
{
|
|
||||||
LagCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderSound)
|
|
||||||
{
|
|
||||||
ProcessSoundEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Frame
|
|
||||||
{
|
|
||||||
get => _timeFrameCounter;
|
|
||||||
private set => _timeFrameCounter = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string SystemId { get; }
|
|
||||||
public bool DeterministicEmulation => true;
|
|
||||||
|
|
||||||
public void ResetCounters()
|
|
||||||
{
|
|
||||||
_timeFrameCounter = 0;
|
|
||||||
LagCount = 0;
|
|
||||||
IsLagFrame = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Api.Dispose();
|
|
||||||
_blipL.Dispose();
|
|
||||||
_blipR.Dispose();
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : IInputPollable
|
|
||||||
{
|
|
||||||
public int LagCount { get; set; }
|
|
||||||
|
|
||||||
public bool IsLagFrame { get; set; }
|
|
||||||
|
|
||||||
// TODO: optimize managed to unmanaged using the ActiveChanged event
|
|
||||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,227 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore
|
|
||||||
{
|
|
||||||
private readonly List<MemoryDomain> _memoryDomainList = new List<MemoryDomain>();
|
|
||||||
private IMemoryDomains _memoryDomains;
|
|
||||||
private LibsnesApi.SNES_MAPPER? _mapper;
|
|
||||||
private LibsnesApi.SNES_REGION? _region;
|
|
||||||
|
|
||||||
// works for WRAM, garbage for anything else
|
|
||||||
private static int? FakeBusMap(int addr)
|
|
||||||
{
|
|
||||||
addr &= 0xffffff;
|
|
||||||
int bank = addr >> 16;
|
|
||||||
if (bank == 0x7e || bank == 0x7f)
|
|
||||||
{
|
|
||||||
return addr & 0x1ffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
bank &= 0x7f;
|
|
||||||
int low = addr & 0xffff;
|
|
||||||
if (bank < 0x40 && low < 0x2000)
|
|
||||||
{
|
|
||||||
return low;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupMemoryDomains(byte[] romData, byte[] sgbRomData)
|
|
||||||
{
|
|
||||||
MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, MemoryDomain.Endian.Little);
|
|
||||||
MakeMemoryDomain("CARTROM", LibsnesApi.SNES_MEMORY.CARTRIDGE_ROM, MemoryDomain.Endian.Little, byteSize: 2); //there are signs this doesnt work on SGB?
|
|
||||||
MakeMemoryDomain("CARTRAM", LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM, MemoryDomain.Endian.Little, byteSize: 2);
|
|
||||||
MakeMemoryDomain("SA1 IRAM", LibsnesApi.SNES_MEMORY.SA1_IRAM, MemoryDomain.Endian.Little, byteSize: 2);
|
|
||||||
MakeMemoryDomain("VRAM", LibsnesApi.SNES_MEMORY.VRAM, MemoryDomain.Endian.Little, byteSize: 2);
|
|
||||||
MakeMemoryDomain("OAM", LibsnesApi.SNES_MEMORY.OAM, MemoryDomain.Endian.Little, byteSize: 2);
|
|
||||||
MakeMemoryDomain("CGRAM", LibsnesApi.SNES_MEMORY.CGRAM, MemoryDomain.Endian.Little, byteSize: 2);
|
|
||||||
MakeMemoryDomain("APURAM", LibsnesApi.SNES_MEMORY.APURAM, MemoryDomain.Endian.Little, byteSize: 2);
|
|
||||||
|
|
||||||
if (!DeterministicEmulation)
|
|
||||||
{
|
|
||||||
_memoryDomainList.Add(new MemoryDomainDelegate(
|
|
||||||
"System Bus",
|
|
||||||
0x1000000,
|
|
||||||
MemoryDomain.Endian.Little,
|
|
||||||
addr => Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr),
|
|
||||||
(addr, val) => Api.QUERY_poke(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr, val), wordSize: 2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// limited function bus
|
|
||||||
MakeFakeBus();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsSGB)
|
|
||||||
{
|
|
||||||
// NOTE: CGB has 32K of wram, and DMG has 8KB of wram. Not sure how to control this right now.. bsnes might not have any ready way of doign that? I couldnt spot it.
|
|
||||||
// You wouldnt expect a DMG game to access excess wram, but what if it tried to? maybe an oversight in bsnes?
|
|
||||||
MakeMemoryDomain("SGB WRAM", LibsnesApi.SNES_MEMORY.SGB_WRAM, MemoryDomain.Endian.Little);
|
|
||||||
|
|
||||||
//uhhh why can't this be done with MakeMemoryDomain? improve that.
|
|
||||||
var romDomain = new MemoryDomainByteArray("SGB CARTROM", MemoryDomain.Endian.Little, romData, true, 1);
|
|
||||||
_memoryDomainList.Add(romDomain);
|
|
||||||
|
|
||||||
// the last 1 byte of this is special.. its an interrupt enable register, instead of ram. weird. maybe its actually ram and just getting specially used?
|
|
||||||
MakeMemoryDomain("SGB HRAM", LibsnesApi.SNES_MEMORY.SGB_HRAM, MemoryDomain.Endian.Little);
|
|
||||||
|
|
||||||
MakeMemoryDomain("SGB CARTRAM", LibsnesApi.SNES_MEMORY.SGB_CARTRAM, MemoryDomain.Endian.Little);
|
|
||||||
}
|
|
||||||
|
|
||||||
_memoryDomainList.Add(Api.GetPagesDomain());
|
|
||||||
|
|
||||||
_memoryDomains = new MemoryDomainList(_memoryDomainList);
|
|
||||||
((BasicServiceProvider) ServiceProvider).Register(_memoryDomains);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe void MakeMemoryDomain(string name, LibsnesApi.SNES_MEMORY id, MemoryDomain.Endian endian, int byteSize = 1)
|
|
||||||
{
|
|
||||||
int size = Api.QUERY_get_memory_size(id);
|
|
||||||
|
|
||||||
// if this type of memory isn't available, don't make the memory domain (most commonly save ram)
|
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte* blockPtr = Api.QUERY_get_memory_data(id);
|
|
||||||
|
|
||||||
var md = new MemoryDomainIntPtrMonitor(name, MemoryDomain.Endian.Little, (IntPtr)blockPtr, size,
|
|
||||||
true,
|
|
||||||
byteSize, Api);
|
|
||||||
|
|
||||||
_memoryDomainList.Add(md);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe void MakeFakeBus()
|
|
||||||
{
|
|
||||||
int size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.WRAM);
|
|
||||||
if (size != 0x20000)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte* blockPtr = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.WRAM);
|
|
||||||
|
|
||||||
var md = new MemoryDomainDelegate("System Bus", 0x1000000, MemoryDomain.Endian.Little,
|
|
||||||
addr =>
|
|
||||||
{
|
|
||||||
using (Api.EnterExit())
|
|
||||||
{
|
|
||||||
var a = FakeBusMap((int)addr);
|
|
||||||
if (a.HasValue)
|
|
||||||
{
|
|
||||||
return blockPtr[a.Value];
|
|
||||||
}
|
|
||||||
|
|
||||||
return FakeBusRead((int)addr);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(addr, val) =>
|
|
||||||
{
|
|
||||||
using (Api.EnterExit())
|
|
||||||
{
|
|
||||||
var a = FakeBusMap((int)addr);
|
|
||||||
if (a.HasValue)
|
|
||||||
blockPtr[a.Value] = val;
|
|
||||||
}
|
|
||||||
}, wordSize: 2);
|
|
||||||
_memoryDomainList.Add(md);
|
|
||||||
}
|
|
||||||
|
|
||||||
// works for ROM, garbage for anything else
|
|
||||||
private byte FakeBusRead(int addr)
|
|
||||||
{
|
|
||||||
addr &= 0xffffff;
|
|
||||||
int bank = addr >> 16;
|
|
||||||
int low = addr & 0xffff;
|
|
||||||
|
|
||||||
if (!_mapper.HasValue)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (_mapper)
|
|
||||||
{
|
|
||||||
case LibsnesApi.SNES_MAPPER.LOROM:
|
|
||||||
if (low >= 0x8000)
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.EXLOROM:
|
|
||||||
if ((bank >= 0x40 && bank <= 0x7f) || low >= 0x8000)
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.HIROM:
|
|
||||||
case LibsnesApi.SNES_MAPPER.EXHIROM:
|
|
||||||
if ((bank >= 0x40 && bank <= 0x7f) || bank >= 0xc0 || low >= 0x8000)
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.SUPERFXROM:
|
|
||||||
if (bank is (>= 0x40 and <= 0x5F) or (>= 0xC0 and <= 0xDF)
|
|
||||||
|| (low >= 0x8000 && bank is (>= 0x00 and <= 0x3F) or (>= 0x80 and <= 0xBF)))
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.SA1ROM:
|
|
||||||
if (bank >= 0xc0 || (low >= 0x8000 && ((bank >= 0x00 && bank <= 0x3f) || (bank >= 0x80 && bank <= 0xbf))))
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.BSCLOROM:
|
|
||||||
if (low >= 0x8000 && ((bank >= 0x00 && bank <= 0x3f) || (bank >= 0x80 && bank <= 0xbf)))
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.BSCHIROM:
|
|
||||||
if (bank is (>= 0x40 and <= 0x5F) or (>= 0xC0 and <= 0xDF)
|
|
||||||
|| (low >= 0x8000 && bank is (>= 0x00 and <= 0x1F) or (>= 0x80 and <= 0x9F)))
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.BSXROM:
|
|
||||||
if (bank is (>= 0x40 and <= 0x7F) or >= 0xC0
|
|
||||||
|| (low >= 0x8000 && bank is (>= 0x00 and <= 0x3F) or (>= 0x80 and <= 0xBF))
|
|
||||||
|| (low is >= 0x6000 and <= 0x7FFF && bank is >= 0x20 and <= 0x3F))
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesApi.SNES_MAPPER.STROM:
|
|
||||||
if (low >= 0x8000 && ((bank >= 0x00 && bank <= 0x5f) || (bank >= 0x80 && bank <= 0xdf)))
|
|
||||||
{
|
|
||||||
return Api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException($"Unknown mapper: {_mapper}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : IRegionable
|
|
||||||
{
|
|
||||||
public DisplayType Region => _region == LibsnesApi.SNES_REGION.NTSC
|
|
||||||
? DisplayType.NTSC
|
|
||||||
: DisplayType.PAL;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
using BizHawk.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public unsafe partial class LibsnesCore : ISaveRam
|
|
||||||
{
|
|
||||||
public bool SaveRamModified =>
|
|
||||||
Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM) != 0
|
|
||||||
|| Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM) != 0;
|
|
||||||
|
|
||||||
public byte[] CloneSaveRam()
|
|
||||||
{
|
|
||||||
using (Api.EnterExit())
|
|
||||||
{
|
|
||||||
byte* buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
|
||||||
var size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
|
||||||
if (buf == null && Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM) > 0)
|
|
||||||
{
|
|
||||||
buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
|
|
||||||
size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret = new byte[size];
|
|
||||||
Marshal.Copy((IntPtr)buf, ret, 0, size);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StoreSaveRam(byte[] data)
|
|
||||||
{
|
|
||||||
using (Api.EnterExit())
|
|
||||||
{
|
|
||||||
byte* buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
|
||||||
var size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM);
|
|
||||||
if (buf == null)
|
|
||||||
{
|
|
||||||
buf = Api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
|
|
||||||
size = Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size != data.Length)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Somehow, we got a mismatch between saveram size and what bsnes says the saveram size is");
|
|
||||||
}
|
|
||||||
|
|
||||||
Marshal.Copy(data, 0, (IntPtr)buf, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>
|
|
||||||
{
|
|
||||||
public SnesSettings GetSettings()
|
|
||||||
{
|
|
||||||
return _settings.Clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
IBSNESForGfxDebugger.SettingsObj IBSNESForGfxDebugger.GetSettings()
|
|
||||||
=> GetSettings();
|
|
||||||
|
|
||||||
public SnesSyncSettings GetSyncSettings()
|
|
||||||
{
|
|
||||||
return _syncSettings.Clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PutSettingsDirtyBits PutSettings(SnesSettings o)
|
|
||||||
{
|
|
||||||
bool refreshNeeded = o.Palette != _settings.Palette;
|
|
||||||
_settings = o;
|
|
||||||
if (refreshNeeded)
|
|
||||||
{
|
|
||||||
RefreshPalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
return PutSettingsDirtyBits.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IBSNESForGfxDebugger.PutSettings(IBSNESForGfxDebugger.SettingsObj s)
|
|
||||||
=> PutSettings((SnesSettings) s);
|
|
||||||
|
|
||||||
public PutSettingsDirtyBits PutSyncSettings(SnesSyncSettings o)
|
|
||||||
{
|
|
||||||
bool ret = o.LeftPort != _syncSettings.LeftPort
|
|
||||||
|| o.RightPort != _syncSettings.RightPort
|
|
||||||
|| o.LimitAnalogChangeSensitivity != _syncSettings.LimitAnalogChangeSensitivity
|
|
||||||
|| o.RandomizedInitialState != _syncSettings.RandomizedInitialState;
|
|
||||||
|
|
||||||
_syncSettings = o;
|
|
||||||
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SnesSettings _settings;
|
|
||||||
private SnesSyncSettings _syncSettings;
|
|
||||||
|
|
||||||
public class SnesSettings : IBSNESForGfxDebugger.SettingsObj
|
|
||||||
{
|
|
||||||
public bool ShowBG1_0 { get; set; } = true;
|
|
||||||
public bool ShowBG2_0 { get; set; } = true;
|
|
||||||
public bool ShowBG3_0 { get; set; } = true;
|
|
||||||
public bool ShowBG4_0 { get; set; } = true;
|
|
||||||
public bool ShowBG1_1 { get; set; } = true;
|
|
||||||
public bool ShowBG2_1 { get; set; } = true;
|
|
||||||
public bool ShowBG3_1 { get; set; } = true;
|
|
||||||
public bool ShowBG4_1 { get; set; } = true;
|
|
||||||
public bool ShowOBJ_0 { get; set; } = true;
|
|
||||||
public bool ShowOBJ_1 { get; set; } = true;
|
|
||||||
public bool ShowOBJ_2 { get; set; } = true;
|
|
||||||
public bool ShowOBJ_3 { get; set; } = true;
|
|
||||||
|
|
||||||
public bool CropSGBFrame { get; set; } = false;
|
|
||||||
public bool AlwaysDoubleSize { get; set; } = false;
|
|
||||||
public string Palette { get; set; } = "BizHawk";
|
|
||||||
|
|
||||||
public SnesSettings Clone()
|
|
||||||
{
|
|
||||||
return (SnesSettings)MemberwiseClone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SnesSyncSettings
|
|
||||||
{
|
|
||||||
public LibsnesControllerDeck.ControllerType LeftPort { get; set; } = LibsnesControllerDeck.ControllerType.Gamepad;
|
|
||||||
public LibsnesControllerDeck.ControllerType RightPort { get; set; } = LibsnesControllerDeck.ControllerType.Unplugged;
|
|
||||||
|
|
||||||
public bool LimitAnalogChangeSensitivity { get; set; } = true;
|
|
||||||
|
|
||||||
public bool RandomizedInitialState { get; set; } = true;
|
|
||||||
|
|
||||||
public SnesSyncSettings Clone()
|
|
||||||
{
|
|
||||||
return (SnesSyncSettings)MemberwiseClone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : ISoundProvider
|
|
||||||
{
|
|
||||||
private readonly BlipBuffer _blipL = new(4096);
|
|
||||||
private readonly BlipBuffer _blipR = new(4096);
|
|
||||||
private short _latchL, _latchR;
|
|
||||||
private readonly short[] _sampleBuffer = new short[4096];
|
|
||||||
private uint _inSamps;
|
|
||||||
private int _outSamps;
|
|
||||||
|
|
||||||
public void DiscardSamples()
|
|
||||||
{
|
|
||||||
_outSamps = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
|
||||||
{
|
|
||||||
samples = _sampleBuffer;
|
|
||||||
nsamp = _outSamps;
|
|
||||||
DiscardSamples();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitAudio()
|
|
||||||
{
|
|
||||||
_blipL.SetRates(32040.5, 44100);
|
|
||||||
_blipR.SetRates(32040.5, 44100);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void snes_audio_sample(short left, short right)
|
|
||||||
{
|
|
||||||
if (_latchL != left)
|
|
||||||
{
|
|
||||||
_blipL.AddDelta(_inSamps, _latchL - left);
|
|
||||||
_latchL = left;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_latchR != right)
|
|
||||||
{
|
|
||||||
_blipR.AddDelta(_inSamps, _latchR - right);
|
|
||||||
_latchR = right;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inSamps++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessSoundEnd()
|
|
||||||
{
|
|
||||||
_blipL.EndFrame(_inSamps);
|
|
||||||
_blipR.EndFrame(_inSamps);
|
|
||||||
_inSamps = 0;
|
|
||||||
|
|
||||||
_outSamps = _blipL.SamplesAvailable();
|
|
||||||
if (_outSamps != _blipR.SamplesAvailable())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Audio processing error");
|
|
||||||
}
|
|
||||||
|
|
||||||
_blipL.ReadSamplesLeft(_sampleBuffer, _outSamps);
|
|
||||||
_blipR.ReadSamplesRight(_sampleBuffer, _outSamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanProvideAsync => false;
|
|
||||||
|
|
||||||
public void GetSamplesAsync(short[] samples)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Async mode is not supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
|
||||||
|
|
||||||
public void SetSyncMode(SyncSoundMode mode)
|
|
||||||
{
|
|
||||||
if (mode == SyncSoundMode.Async)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Async mode is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : IStatable
|
|
||||||
{
|
|
||||||
public bool AvoidRewind => false;
|
|
||||||
|
|
||||||
public void SaveStateBinary(BinaryWriter writer)
|
|
||||||
{
|
|
||||||
Api.SaveStateBinary(writer);
|
|
||||||
writer.Write(IsLagFrame);
|
|
||||||
writer.Write(LagCount);
|
|
||||||
writer.Write(Frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadStateBinary(BinaryReader reader)
|
|
||||||
{
|
|
||||||
Api.LoadStateBinary(reader);
|
|
||||||
IsLagFrame = reader.ReadBoolean();
|
|
||||||
LagCount = reader.ReadInt32();
|
|
||||||
Frame = reader.ReadInt32();
|
|
||||||
Api.QUERY_set_cdl(_currCdl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
public partial class LibsnesCore : IVideoProvider
|
|
||||||
{
|
|
||||||
public int VirtualWidth { get; private set; } = 293;
|
|
||||||
|
|
||||||
public int VirtualHeight { get; private set; } = 224;
|
|
||||||
|
|
||||||
public int BufferWidth => _videoWidth;
|
|
||||||
|
|
||||||
public int BufferHeight => _videoHeight;
|
|
||||||
|
|
||||||
public int BackgroundColor => 0;
|
|
||||||
|
|
||||||
public int[] GetVideoBuffer() => _videoBuffer;
|
|
||||||
|
|
||||||
public int VsyncNumerator { get; }
|
|
||||||
public int VsyncDenominator { get; }
|
|
||||||
|
|
||||||
private int[] _videoBuffer = new int[256 * 224];
|
|
||||||
private int _videoWidth = 256;
|
|
||||||
private int _videoHeight = 224;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,631 +0,0 @@
|
||||||
using System.Linq;
|
|
||||||
using System.Xml;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Common.PathExtensions;
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
using BizHawk.Emulation.Cores.Components.W65816;
|
|
||||||
|
|
||||||
// TODO - add serializer (?)
|
|
||||||
|
|
||||||
// http://wiki.superfamicom.org/snes/show/Backgrounds
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// libsnes needs to be modified to support multiple instances - THIS IS NECESSARY - or else loading one game and then another breaks things
|
|
||||||
// edit - this is a lot of work
|
|
||||||
// wrap dll code around some kind of library-accessing interface so that it doesn't malfunction if the dll is unavailable
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|
||||||
{
|
|
||||||
[PortedCore(CoreNames.Bsnes, "byuu", "v87", "https://github.com/bsnes-emu/bsnes/tree/v087")]
|
|
||||||
public unsafe partial class LibsnesCore : IEmulator, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ICodeDataLogger,
|
|
||||||
IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>, IBSNESForGfxDebugger
|
|
||||||
{
|
|
||||||
[CoreConstructor(VSystemID.Raw.SGB)]
|
|
||||||
[CoreConstructor(VSystemID.Raw.SNES)]
|
|
||||||
public LibsnesCore(GameInfo game, byte[] rom, CoreComm comm,
|
|
||||||
LibsnesCore.SnesSettings settings, LibsnesCore.SnesSyncSettings syncSettings)
|
|
||||||
:this(game, rom, null, null, comm, settings, syncSettings)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public LibsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm,
|
|
||||||
LibsnesCore.SnesSettings settings, LibsnesCore.SnesSyncSettings syncSettings)
|
|
||||||
{
|
|
||||||
_baseRomPath = baseRomPath;
|
|
||||||
var ser = new BasicServiceProvider(this);
|
|
||||||
ServiceProvider = ser;
|
|
||||||
|
|
||||||
const string TRACE_HEADER = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, DB, flags (NVMXDIZC), V, H)";
|
|
||||||
_tracer = new TraceBuffer(TRACE_HEADER);
|
|
||||||
|
|
||||||
ser.Register<IDisassemblable>(new W65816_DisassemblerService());
|
|
||||||
|
|
||||||
_game = game;
|
|
||||||
CoreComm = comm;
|
|
||||||
byte[] sgbRomData = null;
|
|
||||||
|
|
||||||
if (game.System == VSystemID.Raw.SGB)
|
|
||||||
{
|
|
||||||
if ((romData[0x143] & 0xc0) == 0xc0)
|
|
||||||
{
|
|
||||||
throw new CGBNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
sgbRomData = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB"), "SGB Rom is required for SGB emulation.");
|
|
||||||
game.FirmwareHash = SHA1Checksum.ComputeDigestHex(sgbRomData);
|
|
||||||
}
|
|
||||||
|
|
||||||
_settings = settings ?? new SnesSettings();
|
|
||||||
_syncSettings = syncSettings ?? new SnesSyncSettings();
|
|
||||||
|
|
||||||
_videocb = snes_video_refresh;
|
|
||||||
_inputpollcb = snes_input_poll;
|
|
||||||
_inputstatecb = snes_input_state;
|
|
||||||
_inputnotifycb = snes_input_notify;
|
|
||||||
_scanlineStartCb = snes_scanlineStart;
|
|
||||||
_tracecb = snes_trace;
|
|
||||||
_soundcb = snes_audio_sample;
|
|
||||||
_pathrequestcb = snes_path_request;
|
|
||||||
|
|
||||||
// TODO: pass profile here
|
|
||||||
Api = new(PathUtils.DllDirectoryPath, CoreComm, new Delegate[]
|
|
||||||
{
|
|
||||||
_videocb,
|
|
||||||
_inputpollcb,
|
|
||||||
_inputstatecb,
|
|
||||||
_inputnotifycb,
|
|
||||||
_scanlineStartCb,
|
|
||||||
_tracecb,
|
|
||||||
_soundcb,
|
|
||||||
_pathrequestcb
|
|
||||||
})
|
|
||||||
{
|
|
||||||
ReadHook = ReadHook,
|
|
||||||
ExecHook = ExecHook,
|
|
||||||
WriteHook = WriteHook,
|
|
||||||
ReadHook_SMP = ReadHook_SMP,
|
|
||||||
ExecHook_SMP = ExecHook_SMP,
|
|
||||||
WriteHook_SMP = WriteHook_SMP,
|
|
||||||
};
|
|
||||||
|
|
||||||
ScanlineHookManager = new MyScanlineHookManager(this);
|
|
||||||
|
|
||||||
_controllerDeck = new LibsnesControllerDeck(_syncSettings);
|
|
||||||
_controllerDeck.NativeInit(Api);
|
|
||||||
|
|
||||||
Api.CMD_init(_syncSettings.RandomizedInitialState);
|
|
||||||
|
|
||||||
Api.QUERY_set_path_request(_pathrequestcb);
|
|
||||||
|
|
||||||
// start up audio resampler
|
|
||||||
InitAudio();
|
|
||||||
|
|
||||||
// strip header
|
|
||||||
if ((romData?.Length & 0x7FFF) == 512)
|
|
||||||
{
|
|
||||||
var newData = new byte[romData.Length - 512];
|
|
||||||
Array.Copy(romData, 512, newData, 0, newData.Length);
|
|
||||||
romData = newData;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game.System == VSystemID.Raw.SGB)
|
|
||||||
{
|
|
||||||
IsSGB = true;
|
|
||||||
SystemId = VSystemID.Raw.SNES;
|
|
||||||
ser.Register<IBoardInfo>(new SGBBoardInfo());
|
|
||||||
|
|
||||||
_currLoadParams = new LoadParams
|
|
||||||
{
|
|
||||||
type = LoadParamType.SuperGameBoy,
|
|
||||||
rom_xml = null,
|
|
||||||
rom_data = sgbRomData,
|
|
||||||
rom_size = (uint)sgbRomData.Length,
|
|
||||||
dmg_data = romData,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!LoadCurrent())
|
|
||||||
{
|
|
||||||
throw new Exception("snes_load_cartridge_normal() failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we may need to get some information out of the cart, even during the following bootup/load process
|
|
||||||
if (xmlData != null)
|
|
||||||
{
|
|
||||||
_romxml = new XmlDocument();
|
|
||||||
_romxml.Load(new MemoryStream(xmlData));
|
|
||||||
|
|
||||||
// bsnes wont inspect the xml to load the necessary sfc file.
|
|
||||||
// so, we have to do that here and pass it in as the romData :/
|
|
||||||
if (_romxml["cartridge"]?["rom"] != null)
|
|
||||||
{
|
|
||||||
romData = File.ReadAllBytes(PathSubfile(_romxml["cartridge"]["rom"].Attributes["name"].Value));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception("Could not find rom file specification in xml file. Please check the integrity of your xml file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemId = VSystemID.Raw.SNES;
|
|
||||||
_currLoadParams = new LoadParams
|
|
||||||
{
|
|
||||||
type = LoadParamType.Normal,
|
|
||||||
xml_data = xmlData,
|
|
||||||
rom_data = romData
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!LoadCurrent())
|
|
||||||
{
|
|
||||||
throw new Exception("snes_load_cartridge_normal() failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_region == LibsnesApi.SNES_REGION.NTSC)
|
|
||||||
{
|
|
||||||
// similar to what aviout reports from snes9x and seems logical from bsnes first principles. bsnes uses that numerator (ntsc master clockrate) for sure.
|
|
||||||
VsyncNumerator = 21477272;
|
|
||||||
VsyncDenominator = 4 * 341 * 262;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// http://forums.nesdev.com/viewtopic.php?t=5367&start=19
|
|
||||||
VsyncNumerator = 21281370;
|
|
||||||
VsyncDenominator = 4 * 341 * 312;
|
|
||||||
}
|
|
||||||
|
|
||||||
Api.CMD_power();
|
|
||||||
|
|
||||||
SetupMemoryDomains(romData, sgbRomData);
|
|
||||||
|
|
||||||
if (CurrentProfile == "Compatibility")
|
|
||||||
{
|
|
||||||
ser.Register<ITraceable>(_tracer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Api.QUERY_set_path_request(null);
|
|
||||||
Api.QUERY_set_video_refresh(_videocb);
|
|
||||||
Api.QUERY_set_input_poll(_inputpollcb);
|
|
||||||
Api.QUERY_set_input_state(_inputstatecb);
|
|
||||||
Api.QUERY_set_input_notify(_inputnotifycb);
|
|
||||||
Api.QUERY_set_audio_sample(_soundcb);
|
|
||||||
Api.Seal();
|
|
||||||
RefreshPalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly LibsnesApi.snes_video_refresh_t _videocb;
|
|
||||||
private readonly LibsnesApi.snes_input_poll_t _inputpollcb;
|
|
||||||
private readonly LibsnesApi.snes_input_state_t _inputstatecb;
|
|
||||||
private readonly LibsnesApi.snes_input_notify_t _inputnotifycb;
|
|
||||||
private readonly LibsnesApi.snes_path_request_t _pathrequestcb;
|
|
||||||
|
|
||||||
internal CoreComm CoreComm { get; }
|
|
||||||
|
|
||||||
private readonly string _baseRomPath = "";
|
|
||||||
|
|
||||||
private string PathSubfile(string fname) => Path.Combine(_baseRomPath, fname);
|
|
||||||
|
|
||||||
private readonly GameInfo _game;
|
|
||||||
private readonly LibsnesControllerDeck _controllerDeck;
|
|
||||||
private readonly ITraceable _tracer;
|
|
||||||
private readonly XmlDocument _romxml;
|
|
||||||
private readonly LibsnesApi.snes_scanlineStart_t _scanlineStartCb;
|
|
||||||
private readonly LibsnesApi.snes_trace_t _tracecb;
|
|
||||||
private readonly LibsnesApi.snes_audio_sample_t _soundcb;
|
|
||||||
|
|
||||||
private IController _controller;
|
|
||||||
private readonly LoadParams _currLoadParams;
|
|
||||||
private int _timeFrameCounter;
|
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
public bool IsSGB { get; }
|
|
||||||
|
|
||||||
private class SGBBoardInfo : IBoardInfo
|
|
||||||
{
|
|
||||||
public string BoardName => "SGB";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CurrentProfile => "Compatibility"; // We no longer support performance, and accuracy isn't worth the effort so we shall just hardcode this one
|
|
||||||
|
|
||||||
public LibsnesApi Api { get; }
|
|
||||||
|
|
||||||
public SnesColors.ColorType CurrPalette { get; private set; }
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
private readonly LibsnesCore _core;
|
|
||||||
|
|
||||||
public MyScanlineHookManager(LibsnesCore core)
|
|
||||||
{
|
|
||||||
_core = core;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHooksChanged()
|
|
||||||
{
|
|
||||||
_core.OnScanlineHooksChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnScanlineHooksChanged()
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Api.QUERY_set_scanlineStart(ScanlineHookManager.HookCount == 0 ? null : _scanlineStartCb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void snes_scanlineStart(int line)
|
|
||||||
{
|
|
||||||
ScanlineHookManager.HandleScanline(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string snes_path_request(int slot, string hint)
|
|
||||||
{
|
|
||||||
// every rom requests msu1.rom... why? who knows.
|
|
||||||
// also handle msu-1 pcm files here
|
|
||||||
bool isMsu1Rom = hint == "msu1.rom";
|
|
||||||
bool isMsu1Pcm = Path.GetExtension(hint).ToLowerInvariant() == ".pcm";
|
|
||||||
if (isMsu1Rom || isMsu1Pcm)
|
|
||||||
{
|
|
||||||
// well, check if we have an msu-1 xml
|
|
||||||
if (_romxml?["cartridge"]?["msu1"] != null)
|
|
||||||
{
|
|
||||||
var msu1 = _romxml["cartridge"]["msu1"];
|
|
||||||
if (isMsu1Rom && msu1["rom"]?.Attributes["name"] != null)
|
|
||||||
{
|
|
||||||
return PathSubfile(msu1["rom"].Attributes["name"].Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMsu1Pcm)
|
|
||||||
{
|
|
||||||
// return @"D:\roms\snes\SuperRoadBlaster\SuperRoadBlaster-1.pcm";
|
|
||||||
// return "";
|
|
||||||
int wantsTrackNumber = int.Parse(hint.Replace("track-", "").Replace(".pcm", ""));
|
|
||||||
wantsTrackNumber++;
|
|
||||||
string wantsTrackString = wantsTrackNumber.ToString();
|
|
||||||
foreach (var child in msu1.ChildNodes.Cast<XmlNode>())
|
|
||||||
{
|
|
||||||
if (child.Name == "track" && child.Attributes["number"].Value == wantsTrackString)
|
|
||||||
{
|
|
||||||
return PathSubfile(child.Attributes["name"].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// not found.. what to do? (every rom will get here when msu1.rom is requested)
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// not MSU-1. ok.
|
|
||||||
string firmwareId;
|
|
||||||
|
|
||||||
switch (hint)
|
|
||||||
{
|
|
||||||
case "cx4.rom": firmwareId = "CX4"; break;
|
|
||||||
case "dsp1.rom": firmwareId = "DSP1"; break;
|
|
||||||
case "dsp1b.rom": firmwareId = "DSP1b"; break;
|
|
||||||
case "dsp2.rom": firmwareId = "DSP2"; break;
|
|
||||||
case "dsp3.rom": firmwareId = "DSP3"; break;
|
|
||||||
case "dsp4.rom": firmwareId = "DSP4"; break;
|
|
||||||
case "st010.rom": firmwareId = "ST010"; break;
|
|
||||||
case "st011.rom": firmwareId = "ST011"; break;
|
|
||||||
case "st018.rom": firmwareId = "ST018"; break;
|
|
||||||
default:
|
|
||||||
CoreComm.ShowMessage($"Unrecognized SNES firmware request \"{hint}\".");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
string ret;
|
|
||||||
var data = CoreComm.CoreFileProvider.GetFirmware(new("SNES", firmwareId), "Game may function incorrectly without the requested firmware.");
|
|
||||||
if (data != null)
|
|
||||||
{
|
|
||||||
ret = hint;
|
|
||||||
Api.AddReadonlyFile(data, hint);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Served libsnes request for firmware \"{0}\"", hint);
|
|
||||||
|
|
||||||
// return the path we built
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void snes_trace(uint which, string msg)
|
|
||||||
{
|
|
||||||
// TODO: get them out of the core split up and remove this hackery
|
|
||||||
const string splitStr = "A:";
|
|
||||||
|
|
||||||
if (which == (uint)LibsnesApi.eTRACE.CPU)
|
|
||||||
{
|
|
||||||
var split = msg.Split(new[] { splitStr }, 2, StringSplitOptions.None);
|
|
||||||
_tracer.Put(new(disassembly: split[0].PadRight(34), registerInfo: splitStr + split[1]));
|
|
||||||
}
|
|
||||||
else if (which == (uint)LibsnesApi.eTRACE.SMP)
|
|
||||||
{
|
|
||||||
int idx = msg.IndexOf("YA:", StringComparison.Ordinal);
|
|
||||||
_tracer.Put(new(disassembly: msg.Substring(0, idx).TrimEnd(), registerInfo: msg.Substring(idx)));
|
|
||||||
}
|
|
||||||
else if (which == (uint)LibsnesApi.eTRACE.GB)
|
|
||||||
{
|
|
||||||
int idx = msg.IndexOf("AF:", StringComparison.Ordinal);
|
|
||||||
_tracer.Put(new(disassembly: msg.Substring(0, idx).TrimEnd(), registerInfo: msg.Substring(idx)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReadHook(uint addr)
|
|
||||||
{
|
|
||||||
if (MemoryCallbacks.HasReads)
|
|
||||||
{
|
|
||||||
uint flags = (uint)MemoryCallbackFlags.AccessRead;
|
|
||||||
MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus");
|
|
||||||
// we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
|
||||||
// EDIT: for now, theres some IPC re-entrancy problem
|
|
||||||
// RefreshMemoryCallbacks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecHook(uint addr)
|
|
||||||
{
|
|
||||||
if (MemoryCallbacks.HasExecutes)
|
|
||||||
{
|
|
||||||
uint flags = (uint)MemoryCallbackFlags.AccessExecute;
|
|
||||||
MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus");
|
|
||||||
// we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
|
||||||
// EDIT: for now, theres some IPC re-entrancy problem
|
|
||||||
// RefreshMemoryCallbacks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteHook(uint addr, byte val)
|
|
||||||
{
|
|
||||||
if (MemoryCallbacks.HasWrites)
|
|
||||||
{
|
|
||||||
uint flags = (uint)MemoryCallbackFlags.AccessWrite;
|
|
||||||
MemoryCallbacks.CallMemoryCallbacks(addr, val, flags, "System Bus");
|
|
||||||
// we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
|
||||||
// EDIT: for now, theres some IPC re-entrancy problem
|
|
||||||
// RefreshMemoryCallbacks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReadHook_SMP(uint addr)
|
|
||||||
{
|
|
||||||
if (MemoryCallbacks.HasReads)
|
|
||||||
{
|
|
||||||
uint flags = (uint)MemoryCallbackFlags.AccessRead;
|
|
||||||
MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "SMP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecHook_SMP(uint addr)
|
|
||||||
{
|
|
||||||
if (MemoryCallbacks.HasExecutes)
|
|
||||||
{
|
|
||||||
uint flags = (uint)MemoryCallbackFlags.AccessExecute;
|
|
||||||
MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "SMP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteHook_SMP(uint addr, byte val)
|
|
||||||
{
|
|
||||||
if (MemoryCallbacks.HasWrites)
|
|
||||||
{
|
|
||||||
uint flags = (uint)MemoryCallbackFlags.AccessWrite;
|
|
||||||
MemoryCallbacks.CallMemoryCallbacks(addr, val, flags, "SMP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum LoadParamType
|
|
||||||
{
|
|
||||||
Normal, SuperGameBoy
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct LoadParams
|
|
||||||
{
|
|
||||||
public LoadParamType type;
|
|
||||||
public byte[] xml_data;
|
|
||||||
|
|
||||||
public string rom_xml;
|
|
||||||
public byte[] rom_data;
|
|
||||||
public uint rom_size;
|
|
||||||
public byte[] dmg_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool LoadCurrent()
|
|
||||||
{
|
|
||||||
bool result = _currLoadParams.type == LoadParamType.Normal
|
|
||||||
? Api.CMD_load_cartridge_normal(_currLoadParams.xml_data, _currLoadParams.rom_data)
|
|
||||||
: Api.CMD_load_cartridge_super_game_boy(_currLoadParams.rom_xml, _currLoadParams.rom_data, _currLoadParams.rom_size, _currLoadParams.dmg_data);
|
|
||||||
|
|
||||||
_mapper = Api.Mapper;
|
|
||||||
_region = Api.Region;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <param name="port">0 or 1, corresponding to L and R physical ports on the snes</param>
|
|
||||||
/// <param name="device">LibsnesApi.SNES_DEVICE enum index specifying type of device</param>
|
|
||||||
/// <param name="index">meaningless for most controllers. for multitap, 0-3 for which multitap controller</param>
|
|
||||||
/// <param name="id">button ID enum; in the case of a regular controller, this corresponds to shift register position</param>
|
|
||||||
/// <returns>for regular controllers, one bit D0 of button status. for other controls, varying ranges depending on id</returns>
|
|
||||||
private short snes_input_state(int port, int device, int index, int id)
|
|
||||||
{
|
|
||||||
return _controllerDeck.CoreInputState(_controller, port, device, index, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void snes_input_poll()
|
|
||||||
{
|
|
||||||
// this doesn't actually correspond to anything in the underlying bsnes;
|
|
||||||
// it gets called once per frame with video_refresh() and has nothing to do with anything
|
|
||||||
}
|
|
||||||
|
|
||||||
private void snes_input_notify(int index)
|
|
||||||
{
|
|
||||||
// gets called with the following numbers:
|
|
||||||
// 4xxx : lag frame related
|
|
||||||
// 0: signifies latch bit going to 0. should be reported as oninputpoll
|
|
||||||
// 1: signifies latch bit going to 1. should be reported as oninputpoll
|
|
||||||
if (index >= 0x4000)
|
|
||||||
{
|
|
||||||
IsLagFrame = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void snes_video_refresh(int* data, int width, int height)
|
|
||||||
{
|
|
||||||
bool doubleSize = _settings.AlwaysDoubleSize;
|
|
||||||
bool lineDouble = doubleSize, dotDouble = doubleSize;
|
|
||||||
|
|
||||||
_videoWidth = width;
|
|
||||||
_videoHeight = height;
|
|
||||||
|
|
||||||
int yskip = 1, xskip = 1;
|
|
||||||
|
|
||||||
// if we are in high-res mode, we get double width. so, lets double the height here to keep it square.
|
|
||||||
if (width == 512)
|
|
||||||
{
|
|
||||||
_videoHeight *= 2;
|
|
||||||
yskip = 2;
|
|
||||||
|
|
||||||
lineDouble = true;
|
|
||||||
|
|
||||||
// we don't dot double here because the user wanted double res and the game provided double res
|
|
||||||
dotDouble = false;
|
|
||||||
}
|
|
||||||
else if (lineDouble)
|
|
||||||
{
|
|
||||||
_videoHeight *= 2;
|
|
||||||
yskip = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int srcPitch = 1024;
|
|
||||||
int srcStart = 0;
|
|
||||||
|
|
||||||
bool interlaced = height == 478 || height == 448;
|
|
||||||
if (interlaced)
|
|
||||||
{
|
|
||||||
// from bsnes in interlaced mode we have each field side by side
|
|
||||||
// so we will come in with a dimension of 512x448, say
|
|
||||||
// but the fields are side by side, so it's actually 1024x224.
|
|
||||||
// copy the first scanline from row 0, then the 2nd scanline from row 0 (offset 512)
|
|
||||||
// EXAMPLE: yu yu hakushu legal screens
|
|
||||||
// EXAMPLE: World Class Service Super Nintendo Tester (double resolution vertically but not horizontally, in character test the stars should shrink)
|
|
||||||
lineDouble = false;
|
|
||||||
srcPitch = 512;
|
|
||||||
yskip = 1;
|
|
||||||
_videoHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dotDouble)
|
|
||||||
{
|
|
||||||
_videoWidth *= 2;
|
|
||||||
xskip = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_settings.CropSGBFrame && IsSGB)
|
|
||||||
{
|
|
||||||
_videoWidth = 160;
|
|
||||||
_videoHeight = 144;
|
|
||||||
}
|
|
||||||
|
|
||||||
int size = _videoWidth * _videoHeight;
|
|
||||||
if (_videoBuffer.Length != size)
|
|
||||||
{
|
|
||||||
_videoBuffer = new int[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_settings.CropSGBFrame && IsSGB)
|
|
||||||
{
|
|
||||||
int di = 0;
|
|
||||||
for (int y = 0; y < 144; y++)
|
|
||||||
{
|
|
||||||
int si = ((y+39) * srcPitch) + 48;
|
|
||||||
for(int x=0;x<160;x++)
|
|
||||||
_videoBuffer[di++] = data[si++];
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < 2; j++)
|
|
||||||
{
|
|
||||||
if (j == 1 && !dotDouble)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xbonus = j;
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
// potentially do this twice, if we need to line double
|
|
||||||
if (i == 1 && !lineDouble)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bonus = (i * _videoWidth) + xbonus;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
int si = (y * srcPitch) + x + srcStart;
|
|
||||||
int di = y * _videoWidth * yskip + x * xskip + bonus;
|
|
||||||
int rgb = data[si];
|
|
||||||
_videoBuffer[di] = rgb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualHeight = BufferHeight;
|
|
||||||
VirtualWidth = BufferWidth;
|
|
||||||
if (VirtualHeight * 2 < VirtualWidth)
|
|
||||||
VirtualHeight *= 2;
|
|
||||||
if (VirtualHeight > 240)
|
|
||||||
VirtualWidth = 512;
|
|
||||||
VirtualWidth = (int)Math.Round(VirtualWidth * 1.146);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RefreshMemoryCallbacks(bool suppress)
|
|
||||||
{
|
|
||||||
var mcs = MemoryCallbacks;
|
|
||||||
Api.QUERY_set_state_hook_exec(!suppress && mcs.HasExecutesForScope("System Bus"));
|
|
||||||
Api.QUERY_set_state_hook_read(!suppress && mcs.HasReadsForScope("System Bus"));
|
|
||||||
Api.QUERY_set_state_hook_write(!suppress && mcs.HasWritesForScope("System Bus"));
|
|
||||||
}
|
|
||||||
|
|
||||||
//public byte[] snes_get_memory_data_read(LibsnesApi.SNES_MEMORY id)
|
|
||||||
//{
|
|
||||||
// var size = (int)api.snes_get_memory_size(id);
|
|
||||||
// if (size == 0) return new byte[0];
|
|
||||||
// var ret = api.snes_get_memory_data(id);
|
|
||||||
// return ret;
|
|
||||||
//}
|
|
||||||
|
|
||||||
private void RefreshPalette()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -103,7 +103,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
void SetBackColor(int snescol = -1);
|
void SetBackColor(int snescol = -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe class SNESGraphicsDecoder : ISNESGraphicsDecoder
|
public static class SNESGraphicsDecoder
|
||||||
{
|
{
|
||||||
public class PaletteSelection
|
public class PaletteSelection
|
||||||
{
|
{
|
||||||
|
@ -289,59 +289,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
public BGInfo this[int index] => bgs[index - 1];
|
public BGInfo this[int index] => bgs[index - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OAMInfo : ISNESGraphicsDecoder.OAMInfo
|
|
||||||
{
|
|
||||||
public int Index { get; }
|
|
||||||
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; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tiledata address
|
|
||||||
/// </summary>
|
|
||||||
public int Address { get; }
|
|
||||||
|
|
||||||
public OAMInfo(SNESGraphicsDecoder dec, ScreenInfo si, int num)
|
|
||||||
{
|
|
||||||
Index = num;
|
|
||||||
|
|
||||||
int lowaddr = num*4;
|
|
||||||
X = dec.oam[lowaddr++];
|
|
||||||
Y = dec.oam[lowaddr++];
|
|
||||||
byte name = dec.oam[lowaddr++];
|
|
||||||
Table = (dec.oam[lowaddr] & 1) == 1;
|
|
||||||
Palette = (dec.oam[lowaddr]>>1) & 7;
|
|
||||||
Priority = (byte)((dec.oam[lowaddr] >> 4) & 3);
|
|
||||||
HFlip = ((dec.oam[lowaddr] >> 6) & 1) == 1;
|
|
||||||
VFlip = ((dec.oam[lowaddr] >> 7) & 1) == 1;
|
|
||||||
|
|
||||||
int highaddr = num / 4;
|
|
||||||
int shift = (num % 4) * 2;
|
|
||||||
int high = dec.oam[512+highaddr];
|
|
||||||
high >>= shift;
|
|
||||||
int x = high & 1;
|
|
||||||
high >>= 1;
|
|
||||||
Size = (high & 1) != 0;
|
|
||||||
X = (ushort)(X | (x << 8));
|
|
||||||
|
|
||||||
Tile = name + (Table ? 256 : 0);
|
|
||||||
Address = 32 * Tile;
|
|
||||||
|
|
||||||
if (Tile < 256)
|
|
||||||
Address += si.OBJTable0Addr;
|
|
||||||
else
|
|
||||||
Address += si.OBJTable1Addr - (256 * 32);
|
|
||||||
|
|
||||||
Address &= 0xFFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ScreenInfo
|
public class ScreenInfo
|
||||||
{
|
{
|
||||||
public Size ObjSizeBounds;
|
public Size ObjSizeBounds;
|
||||||
|
@ -402,187 +349,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
{8,7,0,0}
|
{8,7,0,0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public ScreenInfo ScanScreenInfo()
|
|
||||||
{
|
|
||||||
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
|
||||||
private static readonly int[] directColorTable = new int[256]; //8bpp gfx -> rgb555
|
private static readonly int[] directColorTable = new int[256]; //8bpp gfx -> rgb555
|
||||||
static SNESGraphicsDecoder()
|
static SNESGraphicsDecoder()
|
||||||
|
@ -601,30 +367,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly int[] colortable;
|
|
||||||
public byte* vram, oam;
|
|
||||||
public ushort* cgram, vram16;
|
|
||||||
|
|
||||||
private readonly LibsnesApi api;
|
|
||||||
|
|
||||||
public SNESGraphicsDecoder(LibsnesApi api, SnesColors.ColorType pal)
|
|
||||||
{
|
|
||||||
this.api = api;
|
|
||||||
colortable = SnesColors.GetLUT(pal);
|
|
||||||
IntPtr block = (IntPtr)api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.VRAM);
|
|
||||||
vram = (byte*)block;
|
|
||||||
vram16 = (ushort*)block;
|
|
||||||
block = (IntPtr)api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.CGRAM);
|
|
||||||
cgram = (ushort*)block;
|
|
||||||
block = (IntPtr)api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.OAM);
|
|
||||||
oam = (byte*)block;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
//todo - unhook from api?
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct TileEntry
|
public struct TileEntry
|
||||||
{
|
{
|
||||||
public ushort tilenum;
|
public ushort tilenum;
|
||||||
|
@ -638,473 +380,5 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
{
|
{
|
||||||
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>
|
|
||||||
/// decodes a mode7 BG. youll still need to paletteize and colorize it.
|
|
||||||
/// </summary>
|
|
||||||
public void DecodeMode7BG(int* screen, int stride, bool extBg)
|
|
||||||
{
|
|
||||||
int[] tileCache = _tileCache[extBg?17:7];
|
|
||||||
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, pix=src; py < 8; py++)
|
|
||||||
{
|
|
||||||
for (int px = 0; px < 8; px++, pix++)
|
|
||||||
{
|
|
||||||
int dst = (ty * 8 + py) * stride + (tx * 8 + px);
|
|
||||||
int srcData = tileCache[pix];
|
|
||||||
screen[dst] = srcData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// returns a tilemap which might be resized into 8x8 physical tiles if the 16x16 logical tilesize is specified
|
|
||||||
// /// </summary>
|
|
||||||
// TileEntry[] AdaptTilemap(TileEntry[] map8x8, int tilesWide, int tilesTall, int tilesize)
|
|
||||||
// {
|
|
||||||
// if (tilesize == 8) return map8x8;
|
|
||||||
// int numTiles = tilesWide * tilesTall;
|
|
||||||
// var ret = new TileEntry[numTiles * 4];
|
|
||||||
// for(int y=0;y<tilesTall;y++)
|
|
||||||
// {
|
|
||||||
// for (int x = 0; x < tilesWide; x++)
|
|
||||||
// {
|
|
||||||
// int si = tilesWide * y + x;
|
|
||||||
// int di = tilesHigh
|
|
||||||
// for (int tx = 0; tx < 2; tx++)
|
|
||||||
// {
|
|
||||||
// for (int ty = 0; ty < 2; ty++)
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// decodes a BG. youll still need to paletteize and colorize it.
|
|
||||||
/// someone else has to take care of calculating the starting color from the mode and layer number.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
|
|
||||||
int[] tileBuf = new int[16*16];
|
|
||||||
var dims = SizeInTilesForBGSize(size);
|
|
||||||
int count8x8 = tilesize / 8;
|
|
||||||
int tileSizeBytes = 8 * bpp;
|
|
||||||
int baseTileNum = tiledataBaseAddr / tileSizeBytes;
|
|
||||||
int[] tileCache = _tileCache[bpp];
|
|
||||||
int tileCacheMask = tileCache.Length - 1;
|
|
||||||
|
|
||||||
int screenWidth = dims.Width * count8x8 * 8;
|
|
||||||
|
|
||||||
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 i = 0, y = 0; y < 8; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < 8; x++, i++)
|
|
||||||
{
|
|
||||||
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 && usingUserBackColor)
|
|
||||||
{ }
|
|
||||||
else
|
|
||||||
{
|
|
||||||
color += te.palette * ncolors;
|
|
||||||
color += paletteStart;
|
|
||||||
}
|
|
||||||
screen[dstOfs] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileEntry[] FetchMode7Tilemap()
|
|
||||||
{
|
|
||||||
TileEntry[] buf = new TileEntry[128*128];
|
|
||||||
for (int ty = 0, tidx = 0; ty < 128; ty++)
|
|
||||||
{
|
|
||||||
for (int tx = 0; tx < 128; tx++, tidx++)
|
|
||||||
{
|
|
||||||
int tileEntry = vram[tidx * 2];
|
|
||||||
buf[tidx].address = tidx * 2;
|
|
||||||
buf[tidx].tilenum = (ushort)tileEntry;
|
|
||||||
//palette and flags are ok defaulting to 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// fetches a tilemap. this is simple; apparently only the screen size (shape) is a factor (not the tile size)
|
|
||||||
/// </summary>
|
|
||||||
public TileEntry[] FetchTilemap(int addr, ScreenSize size)
|
|
||||||
{
|
|
||||||
var blockDims = SizeInBlocksForBGSize(size);
|
|
||||||
int blocksw = blockDims.Width;
|
|
||||||
int blocksh = blockDims.Height;
|
|
||||||
int width = blockDims.Width * 32;
|
|
||||||
int height = blockDims.Height * 32;
|
|
||||||
TileEntry[] buf = new TileEntry[width*height];
|
|
||||||
|
|
||||||
for (int by = 0; by < blocksh; by++)
|
|
||||||
{
|
|
||||||
for (int bx = 0; bx < blocksw; bx++)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < 32; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < 32; x++)
|
|
||||||
{
|
|
||||||
int idx = (by * 32 + y) * width + bx * 32 + x;
|
|
||||||
ushort entry = *(ushort*)(vram + addr);
|
|
||||||
buf[idx].tilenum = (ushort)(entry & 0x3FF);
|
|
||||||
buf[idx].palette = (byte)((entry >> 10) & 7);
|
|
||||||
buf[idx].flags = (TileEntryFlags)((entry >> 13) & 7);
|
|
||||||
buf[idx].address = addr;
|
|
||||||
addr += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO - paletteize and colorize could be in one step, for more speed
|
|
||||||
public void Paletteize(int* buf, int offset, int startcolor, int numpixels)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < numpixels; i++)
|
|
||||||
{
|
|
||||||
int entry = buf[offset + i];
|
|
||||||
int color;
|
|
||||||
if (entry == 0 && usingUserBackColor)
|
|
||||||
color = userBackColor;
|
|
||||||
else color = cgram[startcolor + entry] & 0x7FFF; //unfortunate that we have to mask this here.. maybe do it in a more optimal spot when we port it to c++
|
|
||||||
|
|
||||||
buf[offset + i] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Colorize(int* buf, int offset, int numpixels)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < numpixels; i++)
|
|
||||||
{
|
|
||||||
buf[offset + i] = colortable[491520 + buf[offset + i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly int[][] _tileCache = new int[18][];
|
|
||||||
|
|
||||||
private bool usingUserBackColor;
|
|
||||||
private int userBackColor;
|
|
||||||
|
|
||||||
public void SetBackColor(int snescol)
|
|
||||||
{
|
|
||||||
if (snescol == -1)
|
|
||||||
{
|
|
||||||
usingUserBackColor = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
usingUserBackColor = true;
|
|
||||||
userBackColor = snescol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Caches all tiles at the 2bpp, 4bpp, and 8bpp decoded states.
|
|
||||||
/// we COULD defer this til we need it, you know. sort of a cool idea, not too hard
|
|
||||||
/// </summary>
|
|
||||||
public void CacheTiles()
|
|
||||||
{
|
|
||||||
//generate 2bpp tiles
|
|
||||||
int numtiles = 65536/8/2;
|
|
||||||
int[] tiles = new int[8 * 8 * numtiles];
|
|
||||||
_tileCache[2] = tiles;
|
|
||||||
for (int i = 0; i < numtiles; i++)
|
|
||||||
{
|
|
||||||
Decode8x8x2bpp(tiles, i * 64, 16 * i, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
//merge 2bpp tiles into 4bpp and 8bpp
|
|
||||||
CacheTiles_Merge(2);
|
|
||||||
CacheTiles_Merge(4);
|
|
||||||
CacheTilesMode7();
|
|
||||||
CacheTilesMode7ExtBg();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CacheTilesMode7()
|
|
||||||
{
|
|
||||||
int numtiles = 256;
|
|
||||||
int[] tiles = new int[8 * 8 * numtiles];
|
|
||||||
_tileCache[7] = tiles;
|
|
||||||
for (int i = 0, j=0; i < numtiles; i++)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < 8; y++)
|
|
||||||
for (int x = 0; x < 8; x++, j++)
|
|
||||||
tiles[j] = vram[j * 2 + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//not being used.. do we need it?
|
|
||||||
public int[] GetCachedTile(int bpp, int tilenum)
|
|
||||||
{
|
|
||||||
int[] ret = new int[8 * 8];
|
|
||||||
int idx = tilenum * 64;
|
|
||||||
for (int i = 0; i < 64; i++)
|
|
||||||
ret[i] = _tileCache[bpp][idx + i];
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CacheTilesMode7ExtBg()
|
|
||||||
{
|
|
||||||
int numtiles = 256;
|
|
||||||
int[] tiles = new int[8 * 8 * numtiles];
|
|
||||||
_tileCache[17] = tiles;
|
|
||||||
int[] mode7tiles = _tileCache[7];
|
|
||||||
int numPixels = numtiles*8*8;
|
|
||||||
for (int i = 0; i < numPixels; i++)
|
|
||||||
tiles[i] = mode7tiles[i] & 0x7F;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// merges one type of tiles with another to create the higher-order bitdepth.
|
|
||||||
/// TODO - templateize this when we change it to c++
|
|
||||||
/// </summary>
|
|
||||||
private void CacheTiles_Merge(int fromBpp)
|
|
||||||
{
|
|
||||||
int toBpp = fromBpp * 2;
|
|
||||||
int shift = fromBpp;
|
|
||||||
int numtiles = 8192 / toBpp;
|
|
||||||
int[] tilesDst = new int[8 * 8 * numtiles];
|
|
||||||
_tileCache[toBpp] = tilesDst;
|
|
||||||
int[] tilesSrc = _tileCache[fromBpp];
|
|
||||||
|
|
||||||
for (int i = 0; i < numtiles; i++)
|
|
||||||
{
|
|
||||||
int srcAddr = i * 128;
|
|
||||||
int dstAddr = i * 64;
|
|
||||||
for (int p = 0; p < 64; p++)
|
|
||||||
{
|
|
||||||
int tileA = tilesSrc[srcAddr + p];
|
|
||||||
int tileB = tilesSrc[srcAddr + p + 64];
|
|
||||||
tilesDst[dstAddr + p] = tileA | (tileB << shift);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// decodes an 8x8 tile to a linear framebuffer type thing. fundamental unit of tile decoding.
|
|
||||||
/// </summary>
|
|
||||||
public void Decode8x8x2bpp(int[] buf, int offset, int addr, int stride=8)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < 8; y++)
|
|
||||||
{
|
|
||||||
byte val = vram[addr + 1];
|
|
||||||
for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = val >> (7 - x) & 1;
|
|
||||||
val = vram[addr + 0];
|
|
||||||
for (int x = 0; x < 8; x++) buf[offset + y * stride + x] = (buf[offset + y * stride + x] << 1) | (val >> (7 - x) & 1);
|
|
||||||
addr += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// renders the mode7 tiles to a screen with the predefined size.
|
|
||||||
/// </summary>
|
|
||||||
public void RenderMode7TilesToScreen(int* screen, int stride, bool ext, bool directColor, int tilesWide = 16, int startTile = 0, int numTiles = 256)
|
|
||||||
{
|
|
||||||
int[] tilebuf = _tileCache[ext?17:7];
|
|
||||||
for (int i = 0; i < numTiles; i++)
|
|
||||||
{
|
|
||||||
int tnum = startTile + i;
|
|
||||||
//TODO - mask by possible number of tiles? only in OBJ rendering mode?
|
|
||||||
|
|
||||||
int ty = i / tilesWide;
|
|
||||||
int tx = i % tilesWide;
|
|
||||||
int dstOfs = (ty * 8) * stride + tx * 8;
|
|
||||||
int srcOfs = tnum * 64;
|
|
||||||
for (int y = 0, p = 0; y < 8; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < 8; x++, p++)
|
|
||||||
{
|
|
||||||
screen[dstOfs + y * stride + x] = tilebuf[srcOfs + p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int numPixels = numTiles * 8 * 8;
|
|
||||||
if (directColor) DirectColorify(screen, numPixels);
|
|
||||||
else Paletteize(screen, 0, 0, numPixels);
|
|
||||||
Colorize(screen, 0, numPixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// renders the tiles to a screen of the crudely specified size.
|
|
||||||
/// we might need 16x16 unscrambling and some other perks here eventually.
|
|
||||||
/// provide a start color to use as the basis for the palette
|
|
||||||
/// </summary>
|
|
||||||
public void RenderTilesToScreen(int* screen, int stride, int bpp, int startcolor, int startTile = 0, int numTiles = -1)
|
|
||||||
{
|
|
||||||
if (numTiles == -1)
|
|
||||||
numTiles = 8192 / bpp;
|
|
||||||
int[] tilebuf = _tileCache[bpp];
|
|
||||||
int tilesWide = stride / 8;
|
|
||||||
for (int i = 0; i < numTiles; i++)
|
|
||||||
{
|
|
||||||
int tnum = startTile + i;
|
|
||||||
//TODO - mask by possible number of tiles? only in OBJ rendering mode?
|
|
||||||
int ty = i / tilesWide;
|
|
||||||
int tx = i % tilesWide;
|
|
||||||
int dstOfs = (ty * 8) * stride + tx * 8;
|
|
||||||
int srcOfs = tnum * 64;
|
|
||||||
for (int y = 0, p = 0; y < 8; y++)
|
|
||||||
for (int x = 0; x < 8; x++, p++)
|
|
||||||
{
|
|
||||||
screen[dstOfs + y * stride + x] = tilebuf[srcOfs + p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int numPixels = numTiles * 8 * 8;
|
|
||||||
Paletteize(screen, 0, startcolor, numPixels);
|
|
||||||
Colorize(screen, 0, numPixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
oam ??= new OAMInfo(this, si, spritenum);
|
|
||||||
var dim = ObjSizes[si.OBSEL_Size, oam.Size ? 1 : 0];
|
|
||||||
|
|
||||||
int[] tilebuf = _tileCache[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 x = ox;
|
|
||||||
int y = oy;
|
|
||||||
|
|
||||||
int dy, dx;
|
|
||||||
|
|
||||||
if (oam.HFlip)
|
|
||||||
dx = dim.Width - 1 - x;
|
|
||||||
else dx = x;
|
|
||||||
if (oam.VFlip)
|
|
||||||
dy = dim.Height - 1 - y;
|
|
||||||
else dy = y;
|
|
||||||
|
|
||||||
dx += destx;
|
|
||||||
dy += desty;
|
|
||||||
|
|
||||||
if(dx>=xlimit || dy>=ylimit || dx<0 || dy<0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int col = (bcol + (x >> 3)) & 0xF;
|
|
||||||
int row = (brow + (y >> 3)) & 0xF;
|
|
||||||
int sx = x & 0x7;
|
|
||||||
int sy = y & 0x7;
|
|
||||||
|
|
||||||
int addr = baseaddr*2 + (row * 16 + col) * 64;
|
|
||||||
addr += sy * 8 + sx;
|
|
||||||
|
|
||||||
int dofs = stride*dy+dx;
|
|
||||||
int color = tilebuf[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 int Colorize(int rgb555)
|
|
||||||
{
|
|
||||||
//skip to max luminance in the palette table
|
|
||||||
return colortable[491520 + rgb555];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// returns the current palette, transformed into an int array, for more convenience
|
|
||||||
/// </summary>
|
|
||||||
public int[] GetPalette()
|
|
||||||
{
|
|
||||||
var ret = new int[256];
|
|
||||||
for (int i = 0; i < 256; i++)
|
|
||||||
ret[i] = cgram[i] & 0x7FFF;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DirectColorify(int* screen, int numPixels)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < numPixels; i++)
|
|
||||||
screen[i] = directColorTable[screen[i]];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Enter()
|
|
||||||
{
|
|
||||||
((IMonitor)api).Enter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Exit()
|
|
||||||
{
|
|
||||||
((IMonitor)api).Exit();
|
|
||||||
}
|
|
||||||
} //class SNESGraphicsDecoder
|
} //class SNESGraphicsDecoder
|
||||||
} //namespace
|
} //namespace
|
||||||
|
|
|
@ -12,7 +12,6 @@ namespace BizHawk.Emulation.Cores
|
||||||
public const string A7800Hawk = "A7800Hawk";
|
public const string A7800Hawk = "A7800Hawk";
|
||||||
public const string Ares64 = "Ares64";
|
public const string Ares64 = "Ares64";
|
||||||
public const string Atari2600Hawk = "Atari2600Hawk";
|
public const string Atari2600Hawk = "Atari2600Hawk";
|
||||||
public const string Bsnes = "BSNES";
|
|
||||||
public const string Bsnes115 = "BSNESv115+";
|
public const string Bsnes115 = "BSNESv115+";
|
||||||
public const string C64Hawk = "C64Hawk";
|
public const string C64Hawk = "C64Hawk";
|
||||||
public const string ChannelFHawk = "ChannelFHawk";
|
public const string ChannelFHawk = "ChannelFHawk";
|
||||||
|
|
|
@ -16,7 +16,6 @@ namespace BizHawk.Emulation.Cores
|
||||||
{
|
{
|
||||||
return core switch
|
return core switch
|
||||||
{
|
{
|
||||||
LibsnesCore libsnes => GetLibsnesPadSchemas(libsnes),
|
|
||||||
BsnesCore bsnes => GetBsnesPadSchemas(bsnes),
|
BsnesCore bsnes => GetBsnesPadSchemas(bsnes),
|
||||||
SubBsnesCore subBsnes => GetBsnesPadSchemas(subBsnes.ServiceProvider.GetService<ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>>()),
|
SubBsnesCore subBsnes => GetBsnesPadSchemas(subBsnes.ServiceProvider.GetService<ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>>()),
|
||||||
NymaCore nyma => GetFaustSchemas(nyma, showMessageBox),
|
NymaCore nyma => GetFaustSchemas(nyma, showMessageBox),
|
||||||
|
@ -57,60 +56,6 @@ namespace BizHawk.Emulation.Cores
|
||||||
yield return ConsoleButtons();
|
yield return ConsoleButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<PadSchema> GetLibsnesPadSchemas(LibsnesCore core)
|
|
||||||
{
|
|
||||||
var syncSettings = core.GetSyncSettings();
|
|
||||||
|
|
||||||
var ports = new[]
|
|
||||||
{
|
|
||||||
syncSettings.LeftPort,
|
|
||||||
syncSettings.RightPort
|
|
||||||
};
|
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
int playerNum = i + offset + 1;
|
|
||||||
switch (ports[i])
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case LibsnesControllerDeck.ControllerType.Unplugged:
|
|
||||||
offset -= 1;
|
|
||||||
break;
|
|
||||||
case LibsnesControllerDeck.ControllerType.Gamepad:
|
|
||||||
yield return StandardController(playerNum);
|
|
||||||
break;
|
|
||||||
case LibsnesControllerDeck.ControllerType.Multitap:
|
|
||||||
for (int j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
yield return StandardController(playerNum + j);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += 3;
|
|
||||||
break;
|
|
||||||
case LibsnesControllerDeck.ControllerType.Mouse:
|
|
||||||
yield return Mouse(playerNum);
|
|
||||||
break;
|
|
||||||
case LibsnesControllerDeck.ControllerType.SuperScope:
|
|
||||||
yield return SuperScope(playerNum);
|
|
||||||
break;
|
|
||||||
case LibsnesControllerDeck.ControllerType.Justifier:
|
|
||||||
for (int j = 0; j < 2; j++)
|
|
||||||
{
|
|
||||||
yield return Justifier(playerNum);
|
|
||||||
offset += j;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LibsnesControllerDeck.ControllerType.Payload:
|
|
||||||
yield return Payload(playerNum);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return ConsoleButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<PadSchema> GetBsnesPadSchemas(ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> settingsProvider)
|
private IEnumerable<PadSchema> GetBsnesPadSchemas(ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> settingsProvider)
|
||||||
{
|
{
|
||||||
var syncSettings = settingsProvider.GetSyncSettings();
|
var syncSettings = settingsProvider.GetSyncSettings();
|
||||||
|
@ -231,7 +176,7 @@ namespace BizHawk.Emulation.Cores
|
||||||
|
|
||||||
private static PadSchema Mouse(int controller)
|
private static PadSchema Mouse(int controller)
|
||||||
{
|
{
|
||||||
var defAxes = new SnesMouseController().Definition.Axes;
|
var defAxes = SnesMouseController.Definition.Axes;
|
||||||
return new PadSchema
|
return new PadSchema
|
||||||
{
|
{
|
||||||
Size = new Size(345, 225),
|
Size = new Size(345, 225),
|
||||||
|
|
Loading…
Reference in New Issue