quicknes: support unplugging controllers
This commit is contained in:
parent
01909dfb98
commit
f3e9958f07
|
@ -1216,7 +1216,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
MovieSettingsMenuItem.Enabled =
|
||||
Global.Emulator is NES;
|
||||
|
||||
NesControllerSettingsMenuItem.Enabled = Global.Emulator is NES && !Global.MovieSession.Movie.IsActive;
|
||||
NesControllerSettingsMenuItem.Enabled = (Global.Emulator is NES || Global.Emulator is QuickNES) && !Global.MovieSession.Movie.IsActive;
|
||||
MovieSettingsMenuItem.Enabled = Global.Emulator is NES && !Global.MovieSession.Movie.IsActive;
|
||||
|
||||
barcodeReaderToolStripMenuItem.Enabled = BarcodeEntry.HasReader();
|
||||
|
@ -1285,7 +1285,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void NesControllerSettingsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new NesControllerSettings().ShowDialog();
|
||||
if (Global.Emulator is NES)
|
||||
new NesControllerSettings().ShowDialog();
|
||||
else if (Global.Emulator is QuickNES)
|
||||
GenericCoreConfig.DoDialog(this, "QuickNES Controller Settings", true, false);
|
||||
}
|
||||
|
||||
private void MovieSettingsMenuItem_Click(object sender, EventArgs e)
|
||||
|
|
|
@ -18,15 +18,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
object ss;
|
||||
bool syncsettingschanged = false;
|
||||
|
||||
GenericCoreConfig()
|
||||
GenericCoreConfig(bool ignoresettings, bool ignoresyncsettings)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var settable = new SettingsAdapter(Global.Emulator);
|
||||
|
||||
if (settable.HasSettings)
|
||||
if (settable.HasSettings && !ignoresettings)
|
||||
s = settable.GetSettings();
|
||||
if (settable.HasSyncSettings)
|
||||
if (settable.HasSyncSettings && !ignoresyncsettings)
|
||||
ss = settable.GetSyncSettings();
|
||||
|
||||
if (s != null)
|
||||
|
@ -42,6 +42,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
propertyGrid2.Enabled = false; // disable changes to sync setting when movie, so as not to confuse user
|
||||
}
|
||||
|
||||
GenericCoreConfig()
|
||||
:this(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
{
|
||||
var settable = new SettingsAdapter(Global.Emulator);
|
||||
|
@ -63,6 +68,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
dlg.ShowDialog(owner);
|
||||
}
|
||||
|
||||
public static void DoDialog(IWin32Window owner, string title, bool hidesettings, bool hidesyncsettings)
|
||||
{
|
||||
using (var dlg = new GenericCoreConfig(hidesettings, hidesyncsettings) { Text = title })
|
||||
dlg.ShowDialog(owner);
|
||||
}
|
||||
|
||||
private void propertyGrid2_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
|
||||
{
|
||||
syncsettingschanged = true;
|
||||
|
|
|
@ -285,6 +285,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public bool StartAsyncSound() { return true; }
|
||||
public void EndAsyncSound() { }
|
||||
|
||||
[Obsolete] // with the changes to both nes and quicknes cores, nothing uses this anymore
|
||||
public static readonly ControllerDefinition NESController =
|
||||
new ControllerDefinition
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
}
|
||||
|
||||
[CoreConstructor("NES")]
|
||||
public QuickNES(CoreComm comm, byte[] file, object Settings)
|
||||
public QuickNES(CoreComm comm, byte[] file, object Settings, object SyncSettings)
|
||||
{
|
||||
using (FP.Save())
|
||||
{
|
||||
|
@ -88,6 +88,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
CoreComm.VsyncDen = 655171;
|
||||
PutSettings((QuickNESSettings)Settings ?? new QuickNESSettings());
|
||||
|
||||
_SyncSettings = (QuickNESSyncSettings)SyncSettings ?? new QuickNESSyncSettings();
|
||||
_SyncSettings_next = _SyncSettings.Clone();
|
||||
|
||||
SetControllerDefinition();
|
||||
ComputeBootGod();
|
||||
}
|
||||
catch
|
||||
|
@ -100,45 +104,71 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
|
||||
#region Controller
|
||||
|
||||
public ControllerDefinition ControllerDefinition { get { return Emulation.Cores.Nintendo.NES.NES.NESController; } }
|
||||
public ControllerDefinition ControllerDefinition { get; private set; }
|
||||
public IController Controller { get; set; }
|
||||
|
||||
void SetControllerDefinition()
|
||||
{
|
||||
var def = new ControllerDefinition();
|
||||
def.Name = "NES Controller";
|
||||
def.BoolButtons.AddRange(new[] { "Reset", "Power" }); // console buttons
|
||||
if (_SyncSettings.LeftPortConnected || _SyncSettings.RightPortConnected)
|
||||
def.BoolButtons.AddRange(PadP1.Select(p => p.Name));
|
||||
if (_SyncSettings.LeftPortConnected && _SyncSettings.RightPortConnected)
|
||||
def.BoolButtons.AddRange(PadP2.Select(p => p.Name));
|
||||
ControllerDefinition = def;
|
||||
}
|
||||
|
||||
private struct PadEnt
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly int Mask;
|
||||
public PadEnt(string Name, int Mask)
|
||||
{
|
||||
this.Name = Name;
|
||||
this.Mask = Mask;
|
||||
}
|
||||
}
|
||||
|
||||
private static PadEnt[] GetPadList(int player)
|
||||
{
|
||||
string prefix = string.Format("P{0} ", player);
|
||||
return PadNames.Zip(PadMasks, (s, i) => new PadEnt(prefix + s, i)).ToArray();
|
||||
}
|
||||
|
||||
private static string[] PadNames = new[]
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A"
|
||||
};
|
||||
private static int[] PadMasks = new[]
|
||||
{
|
||||
16, 32, 64, 128, 8, 4, 2, 1
|
||||
};
|
||||
|
||||
private static PadEnt[] PadP1 = GetPadList(1);
|
||||
private static PadEnt[] PadP2 = GetPadList(2);
|
||||
|
||||
private int GetPad(IEnumerable<PadEnt> buttons)
|
||||
{
|
||||
int ret = 0;
|
||||
foreach (var b in buttons)
|
||||
{
|
||||
if (Controller[b.Name])
|
||||
ret |= b.Mask;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SetPads(out int j1, out int j2)
|
||||
{
|
||||
j1 = 0;
|
||||
j2 = 0;
|
||||
if (Controller["P1 A"])
|
||||
j1 |= 1;
|
||||
if (Controller["P1 B"])
|
||||
j1 |= 2;
|
||||
if (Controller["P1 Select"])
|
||||
j1 |= 4;
|
||||
if (Controller["P1 Start"])
|
||||
j1 |= 8;
|
||||
if (Controller["P1 Up"])
|
||||
j1 |= 16;
|
||||
if (Controller["P1 Down"])
|
||||
j1 |= 32;
|
||||
if (Controller["P1 Left"])
|
||||
j1 |= 64;
|
||||
if (Controller["P1 Right"])
|
||||
j1 |= 128;
|
||||
if (Controller["P2 A"])
|
||||
j2 |= 1;
|
||||
if (Controller["P2 B"])
|
||||
j2 |= 2;
|
||||
if (Controller["P2 Select"])
|
||||
j2 |= 4;
|
||||
if (Controller["P2 Start"])
|
||||
j2 |= 8;
|
||||
if (Controller["P2 Up"])
|
||||
j2 |= 16;
|
||||
if (Controller["P2 Down"])
|
||||
j2 |= 32;
|
||||
if (Controller["P2 Left"])
|
||||
j2 |= 64;
|
||||
if (Controller["P2 Right"])
|
||||
j2 |= 128;
|
||||
if (_SyncSettings.LeftPortConnected)
|
||||
j1 = GetPad(PadP1) | unchecked((int)0xffffff00);
|
||||
else
|
||||
j1 = 0;
|
||||
if (_SyncSettings.RightPortConnected)
|
||||
j2 = GetPad(_SyncSettings.LeftPortConnected ? PadP2 : PadP1) | unchecked((int)0xffffff00);
|
||||
else
|
||||
j2 = 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -378,7 +408,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
void ComputeBootGod()
|
||||
{
|
||||
// inefficient, sloppy, etc etc
|
||||
Emulation.Cores.Nintendo.NES.NES.BootGodDB.Initialize();
|
||||
Emulation.Cores.Nintendo.NES.NES.BootGodDB.Initialize();
|
||||
var chrrom = MemoryDomains["CHR VROM"];
|
||||
var prgrom = MemoryDomains["PRG ROM"];
|
||||
|
||||
|
@ -504,17 +534,42 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
}
|
||||
}
|
||||
|
||||
QuickNESSettings _Settings;
|
||||
|
||||
// what is this for?
|
||||
public class QuickNESSyncSettings
|
||||
{
|
||||
[DefaultValue(true)]
|
||||
public bool LeftPortConnected { get; set; }
|
||||
|
||||
[DefaultValue(true)]
|
||||
public bool RightPortConnected { get; set; }
|
||||
|
||||
public QuickNESSyncSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
|
||||
public QuickNESSyncSettings Clone()
|
||||
{
|
||||
return new QuickNESSyncSettings();
|
||||
return (QuickNESSyncSettings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public static bool NeedsReboot(QuickNESSyncSettings x, QuickNESSyncSettings y)
|
||||
{
|
||||
// the core can handle dynamic plugging and unplugging, but that changes
|
||||
// the controllerdefinition, and we're not ready for that
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
QuickNESSettings _Settings;
|
||||
/// <summary>
|
||||
/// the syncsettings that this run of emulation is using (was passed to ctor)
|
||||
/// </summary>
|
||||
QuickNESSyncSettings _SyncSettings;
|
||||
/// <summary>
|
||||
/// the syncsettings that were requested but won't be used yet
|
||||
/// </summary>
|
||||
QuickNESSyncSettings _SyncSettings_next;
|
||||
|
||||
public QuickNESSettings GetSettings()
|
||||
{
|
||||
return _Settings.Clone();
|
||||
|
@ -522,7 +577,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
|
||||
public QuickNESSyncSettings GetSyncSettings()
|
||||
{
|
||||
return new QuickNESSyncSettings();
|
||||
return _SyncSettings_next.Clone();
|
||||
}
|
||||
|
||||
public bool PutSettings(QuickNESSettings o)
|
||||
|
@ -536,7 +591,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
|
||||
public bool PutSyncSettings(QuickNESSyncSettings o)
|
||||
{
|
||||
return false;
|
||||
bool ret = QuickNESSyncSettings.NeedsReboot(_SyncSettings, o);
|
||||
_SyncSettings_next = o;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
Binary file not shown.
|
@ -305,9 +305,9 @@ int Nes_Core::read_io( nes_addr_t addr )
|
|||
// to do: to aid with recording, doesn't emulate transparent latch,
|
||||
// so a game that held strobe at 1 and read $4016 or $4017 would not get
|
||||
// the current A status as occurs on a NES
|
||||
unsigned long result = joypad.joypad_latches [addr & 1];
|
||||
int32_t result = joypad.joypad_latches [addr & 1];
|
||||
if ( !(joypad.w4016 & 1) )
|
||||
joypad.joypad_latches [addr & 1] = (result >> 1) | 0x80000000;
|
||||
joypad.joypad_latches [addr & 1] = result >> 1; // ASR is intentional
|
||||
return result & 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public: private: friend class Nes_Emu;
|
|||
bool sram_present;
|
||||
|
||||
public:
|
||||
unsigned long current_joypad [2];
|
||||
uint32_t current_joypad [2];
|
||||
int joypad_read_count;
|
||||
Nes_Cart const* cart;
|
||||
Nes_Mapper* mapper;
|
||||
|
|
|
@ -124,10 +124,10 @@ void Nes_Emu::set_palette_range( int begin, int end )
|
|||
require( host_palette_size >= palette_alignment );
|
||||
}
|
||||
|
||||
blargg_err_t Nes_Emu::emulate_frame( int joypad1, int joypad2 )
|
||||
blargg_err_t Nes_Emu::emulate_frame( const uint32_t joypad1, const uint32_t joypad2 )
|
||||
{
|
||||
emu.current_joypad [0] = (joypad1 |= ~0xFF);
|
||||
emu.current_joypad [1] = (joypad2 |= ~0xFF);
|
||||
emu.current_joypad [0] = joypad1;
|
||||
emu.current_joypad [1] = joypad2;
|
||||
|
||||
emu.ppu.host_pixels = NULL;
|
||||
|
||||
|
|
|
@ -52,7 +52,10 @@ public:
|
|||
|
||||
// Emulate one video frame using joypad1 and joypad2 as input. Afterwards, image
|
||||
// and sound are available for output using the accessors below.
|
||||
virtual blargg_err_t emulate_frame( int joypad1, int joypad2 = 0 );
|
||||
// A connected controller should have 0xffffff** in the high bits, or 0x000000**
|
||||
// if emulating an incorrectly made third party controller. A disconnected controller
|
||||
// should be 0x00000000 exactly.
|
||||
virtual blargg_err_t emulate_frame( uint32_t joypad1, uint32_t joypad2 );
|
||||
|
||||
// Maximum size of palette that can be generated
|
||||
enum { max_palette_size = 256 };
|
||||
|
|
|
@ -87,7 +87,7 @@ BOOST_STATIC_ASSERT( sizeof (nes_state_t) == 8 );
|
|||
|
||||
struct joypad_state_t
|
||||
{
|
||||
BOOST::uint32_t joypad_latches [2]; // joypad 1 & 2 shift registers
|
||||
uint32_t joypad_latches [2]; // joypad 1 & 2 shift registers
|
||||
byte w4016; // strobe
|
||||
byte unused [3];
|
||||
|
||||
|
|
Loading…
Reference in New Issue