From 66c8e281dd314c69adb5b3e8ef8aad1265c9c77d Mon Sep 17 00:00:00 2001 From: Sour Date: Sat, 30 Apr 2022 14:02:48 -0400 Subject: [PATCH] Config UI, 6-button controller, turbo tap --- Core/Core.vcxproj | 3 + Core/Core.vcxproj.filters | 18 ++- Core/PCE/Input/PceAvenuePad6.h | 130 ++++++++++++++++++ Core/PCE/Input/PceController.h | 30 ++-- Core/PCE/Input/PceTurboTap.cpp | 30 ++++ Core/PCE/Input/PceTurboTap.h | 19 +++ Core/PCE/PceControlManager.cpp | 27 +++- Core/PCE/PceControlManager.h | 2 +- Core/PCE/PceMemoryManager.h | 10 +- Core/PCE/PcePpu.cpp | 16 +-- Core/PCE/PcePpu.h | 12 +- Core/PCE/PcePsg.cpp | 6 +- Core/PCE/PceTypes.h | 5 - Core/Shared/ControllerHub.h | 11 +- Core/Shared/EmuSettings.cpp | 12 ++ Core/Shared/EmuSettings.h | 4 + Core/Shared/SettingTypes.h | 15 ++ InteropDLL/ConfigApiWrapper.cpp | 5 + NewUI/Assets/PceIcon.png | Bin 0 -> 255 bytes NewUI/Config/Configuration.cs | 2 + NewUI/Config/InputConfig.cs | 37 ++--- NewUI/Config/KeyPresets.cs | 20 ++- NewUI/Config/PcEngineConfig.cs | 113 +++++++++++++++ NewUI/Controls/ControllerButton.axaml | 23 ++++ NewUI/Controls/ControllerButton.axaml.cs | 50 +++++++ NewUI/Controls/SystemSpecificSettings.axaml | 1 + .../Controls/SystemSpecificSettings.axaml.cs | 16 +++ .../StatusViews/PceStatusViewModel.cs | 4 +- NewUI/Debugger/Utilities/ContextMenuAction.cs | 2 + .../RegisterViewerWindowViewModel.cs | 2 +- NewUI/Interop/ConfigApi.cs | 1 + NewUI/Interop/DebugState.cs | 8 +- NewUI/Localization/resources.en.xml | 47 ++++++- NewUI/NewUI.csproj | 17 +++ NewUI/ViewModels/ConfigViewModel.cs | 6 +- NewUI/ViewModels/MainMenuViewModel.cs | 4 + NewUI/ViewModels/PceConfigViewModel.cs | 43 ++++++ NewUI/ViewModels/PceInputConfigViewModel.cs | 41 ++++++ NewUI/Views/ControllerConfigViewLocator.cs | 2 + NewUI/Views/GameboyConfigView.axaml | 17 ++- NewUI/Views/PceAvenuePad6View.axaml | 86 ++++++++++++ NewUI/Views/PceAvenuePad6View.axaml.cs | 18 +++ NewUI/Views/PceConfigView.axaml | 76 ++++++++++ NewUI/Views/PceConfigView.axaml.cs | 30 ++++ NewUI/Views/PceControllerView.axaml | 60 ++++++++ NewUI/Views/PceControllerView.axaml.cs | 18 +++ NewUI/Views/PceInputConfigView.axaml | 88 ++++++++++++ NewUI/Views/PceInputConfigView.axaml.cs | 18 +++ NewUI/Windows/ConfigWindow.axaml | 12 ++ 49 files changed, 1117 insertions(+), 100 deletions(-) create mode 100644 Core/PCE/Input/PceAvenuePad6.h create mode 100644 Core/PCE/Input/PceTurboTap.cpp create mode 100644 Core/PCE/Input/PceTurboTap.h create mode 100644 NewUI/Assets/PceIcon.png create mode 100644 NewUI/Config/PcEngineConfig.cs create mode 100644 NewUI/Controls/ControllerButton.axaml create mode 100644 NewUI/Controls/ControllerButton.axaml.cs create mode 100644 NewUI/ViewModels/PceConfigViewModel.cs create mode 100644 NewUI/ViewModels/PceInputConfigViewModel.cs create mode 100644 NewUI/Views/PceAvenuePad6View.axaml create mode 100644 NewUI/Views/PceAvenuePad6View.axaml.cs create mode 100644 NewUI/Views/PceConfigView.axaml create mode 100644 NewUI/Views/PceConfigView.axaml.cs create mode 100644 NewUI/Views/PceControllerView.axaml create mode 100644 NewUI/Views/PceControllerView.axaml.cs create mode 100644 NewUI/Views/PceInputConfigView.axaml create mode 100644 NewUI/Views/PceInputConfigView.axaml.cs diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index e097b7a1..352736fc 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -19,6 +19,8 @@ + + @@ -442,6 +444,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 645aaf0a..1876d1ab 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1760,9 +1760,6 @@ PCE - - PCE - PCE @@ -1799,6 +1796,15 @@ PCE + + PCE\Input + + + PCE\Input + + + PCE\Input + @@ -1870,6 +1876,9 @@ PCE + + PCE\Input + @@ -1878,5 +1887,8 @@ {71cd23d2-e1b9-4a25-a92a-34b2f64f8086} + + {a2cd79a6-585b-408d-b6af-c273b94092a7} + \ No newline at end of file diff --git a/Core/PCE/Input/PceAvenuePad6.h b/Core/PCE/Input/PceAvenuePad6.h new file mode 100644 index 00000000..c9510de0 --- /dev/null +++ b/Core/PCE/Input/PceAvenuePad6.h @@ -0,0 +1,130 @@ +#pragma once +#include "stdafx.h" +#include "Shared/BaseControlDevice.h" +#include "Shared/Emulator.h" +#include "Shared/EmuSettings.h" +#include "Shared/InputHud.h" +#include "Utilities/Serializer.h" + +class PceAvenuePad6 : public BaseControlDevice +{ +private: + uint32_t _turboSpeed = 0; + bool _disableInput = false; + bool _selectDPad = false; + bool _selectExtraButtons = false; + +protected: + string GetKeyNames() override + { + return "UDLRSr123456"; + } + + void InternalSetStateFromInput() override + { + for(KeyMapping& keyMapping : _keyMappings) { + SetPressedState(Buttons::I, keyMapping.A); + SetPressedState(Buttons::II, keyMapping.B); + SetPressedState(Buttons::III, keyMapping.X); + SetPressedState(Buttons::IV, keyMapping.Y); + SetPressedState(Buttons::V, keyMapping.L); + SetPressedState(Buttons::VI, keyMapping.R); + SetPressedState(Buttons::Run, keyMapping.Start); + SetPressedState(Buttons::Select, keyMapping.Select); + SetPressedState(Buttons::Up, keyMapping.Up); + SetPressedState(Buttons::Down, keyMapping.Down); + SetPressedState(Buttons::Left, keyMapping.Left); + SetPressedState(Buttons::Right, keyMapping.Right); + + uint8_t turboFreq = 1 << (4 - _turboSpeed); + bool turboOn = (uint8_t)(_emu->GetFrameCount() % turboFreq) < turboFreq / 2; + if(turboOn) { + SetPressedState(Buttons::I, keyMapping.TurboA); + SetPressedState(Buttons::II, keyMapping.TurboB); + SetPressedState(Buttons::III, keyMapping.TurboX); + SetPressedState(Buttons::IV, keyMapping.TurboY); + SetPressedState(Buttons::V, keyMapping.TurboL); + SetPressedState(Buttons::VI, keyMapping.TurboR); + } + } + } + + void RefreshStateBuffer() override + { + } + +public: + enum Buttons { Up = 0, Down, Left, Right, Select, Run, I, II, III, IV, V, VI }; + + PceAvenuePad6(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::PceAvenuePad6, port, keyMappings) + { + _turboSpeed = keyMappings.TurboSpeed; + } + + uint8_t ReadRam(uint16_t addr) override + { + if(_disableInput) { + return 0; + } + + uint8_t result = 0x0F; + if(_selectExtraButtons) { + if(_selectDPad) { + result = 0; + } else { + result &= ~(IsPressed(PceAvenuePad6::III) ? 0x01 : 0); + result &= ~(IsPressed(PceAvenuePad6::IV) ? 0x02 : 0); + result &= ~(IsPressed(PceAvenuePad6::V) ? 0x04 : 0); + result &= ~(IsPressed(PceAvenuePad6::VI) ? 0x08 : 0); + } + } else { + if(_selectDPad) { + result &= ~(IsPressed(PceAvenuePad6::Up) ? 0x01 : 0); + result &= ~(IsPressed(PceAvenuePad6::Right) ? 0x02 : 0); + result &= ~(IsPressed(PceAvenuePad6::Down) ? 0x04 : 0); + result &= ~(IsPressed(PceAvenuePad6::Left) ? 0x08 : 0); + } else { + result &= ~(IsPressed(PceAvenuePad6::I) ? 0x01 : 0); + result &= ~(IsPressed(PceAvenuePad6::II) ? 0x02 : 0); + result &= ~(IsPressed(PceAvenuePad6::Select) ? 0x04 : 0); + result &= ~(IsPressed(PceAvenuePad6::Run) ? 0x08 : 0); + } + } + + return result; + } + + void WriteRam(uint16_t addr, uint8_t value) override + { + bool disableInput = (value & 0x02) != 0; + if(disableInput && !_disableInput) { + _selectExtraButtons = !_selectExtraButtons; + } + _disableInput = disableInput; + _selectDPad = (value & 0x01) != 0; + } + + void InternalDrawController(InputHud& hud) override + { + hud.DrawOutline(35, 14); + + hud.DrawButton(5, 3, 3, 3, IsPressed(Buttons::Up)); + hud.DrawButton(5, 9, 3, 3, IsPressed(Buttons::Down)); + hud.DrawButton(2, 6, 3, 3, IsPressed(Buttons::Left)); + hud.DrawButton(8, 6, 3, 3, IsPressed(Buttons::Right)); + hud.DrawButton(5, 6, 3, 3, false); + + hud.DrawButton(22, 8, 3, 3, IsPressed(Buttons::III)); + hud.DrawButton(26, 8, 3, 3, IsPressed(Buttons::II)); + hud.DrawButton(30, 8, 3, 3, IsPressed(Buttons::I)); + + hud.DrawButton(22, 3, 3, 3, IsPressed(Buttons::IV)); + hud.DrawButton(26, 3, 3, 3, IsPressed(Buttons::V)); + hud.DrawButton(30, 3, 3, 3, IsPressed(Buttons::VI)); + + hud.DrawButton(12, 9, 4, 2, IsPressed(Buttons::Select)); + hud.DrawButton(17, 9, 4, 2, IsPressed(Buttons::Run)); + + hud.DrawNumber(hud.GetControllerIndex() + 1, 15, 2); + } +}; \ No newline at end of file diff --git a/Core/PCE/Input/PceController.h b/Core/PCE/Input/PceController.h index 091298f3..416a623d 100644 --- a/Core/PCE/Input/PceController.h +++ b/Core/PCE/Input/PceController.h @@ -16,15 +16,15 @@ private: protected: string GetKeyNames() override { - return "UDLRSsBA"; + return "UDLRSr12"; } void InternalSetStateFromInput() override { for(KeyMapping& keyMapping : _keyMappings) { - SetPressedState(Buttons::A, keyMapping.A); - SetPressedState(Buttons::B, keyMapping.B); - SetPressedState(Buttons::Start, keyMapping.Start); + SetPressedState(Buttons::I, keyMapping.A); + SetPressedState(Buttons::II, keyMapping.B); + SetPressedState(Buttons::Run, keyMapping.Start); SetPressedState(Buttons::Select, keyMapping.Select); SetPressedState(Buttons::Up, keyMapping.Up); SetPressedState(Buttons::Down, keyMapping.Down); @@ -34,8 +34,8 @@ protected: uint8_t turboFreq = 1 << (4 - _turboSpeed); bool turboOn = (uint8_t)(_emu->GetFrameCount() % turboFreq) < turboFreq / 2; if(turboOn) { - SetPressedState(Buttons::A, keyMapping.TurboA); - SetPressedState(Buttons::B, keyMapping.TurboB); + SetPressedState(Buttons::I, keyMapping.TurboA); + SetPressedState(Buttons::II, keyMapping.TurboB); } } } @@ -45,9 +45,9 @@ protected: } public: - enum Buttons { Up = 0, Down, Left, Right, Start, Select, B, A }; + enum Buttons { Up = 0, Down, Left, Right, Select, Run, I, II }; - PceController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::GameboyController, port, keyMappings) + PceController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::PceController, port, keyMappings) { _turboSpeed = keyMappings.TurboSpeed; } @@ -65,10 +65,10 @@ public: result &= ~(IsPressed(PceController::Down) ? 0x04 : 0); result &= ~(IsPressed(PceController::Left) ? 0x08 : 0); } else { - result &= ~(IsPressed(PceController::A) ? 0x01 : 0); - result &= ~(IsPressed(PceController::B) ? 0x02 : 0); + result &= ~(IsPressed(PceController::I) ? 0x01 : 0); + result &= ~(IsPressed(PceController::II) ? 0x02 : 0); result &= ~(IsPressed(PceController::Select) ? 0x04 : 0); - result &= ~(IsPressed(PceController::Start) ? 0x08 : 0); + result &= ~(IsPressed(PceController::Run) ? 0x08 : 0); } return result; @@ -90,12 +90,12 @@ public: hud.DrawButton(8, 6, 3, 3, IsPressed(Buttons::Right)); hud.DrawButton(5, 6, 3, 3, false); - hud.DrawButton(30, 7, 3, 3, IsPressed(Buttons::A)); - hud.DrawButton(25, 7, 3, 3, IsPressed(Buttons::B)); + hud.DrawButton(30, 7, 3, 3, IsPressed(Buttons::I)); + hud.DrawButton(25, 7, 3, 3, IsPressed(Buttons::II)); hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select)); - hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start)); + hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Run)); - hud.DrawNumber(_port + 1, 16, 2); + hud.DrawNumber(hud.GetControllerIndex() + 1, 16, 2); } }; \ No newline at end of file diff --git a/Core/PCE/Input/PceTurboTap.cpp b/Core/PCE/Input/PceTurboTap.cpp new file mode 100644 index 00000000..729c0a47 --- /dev/null +++ b/Core/PCE/Input/PceTurboTap.cpp @@ -0,0 +1,30 @@ +#include "stdafx.h" +#include "PceTurboTap.h" + +PceTurboTap::PceTurboTap(Emulator* emu, uint8_t port, ControllerConfig controllers[]) : ControllerHub(emu, ControllerType::PceTurboTap, port, controllers) +{ +} + +uint8_t PceTurboTap::ReadRam(uint16_t addr) +{ + return _ports[_index] ? ReadPort(_index) : 0x0F; +} + +void PceTurboTap::WriteRam(uint16_t addr, uint8_t value) +{ + ControllerHub::WriteRam(addr, value); + bool sel = (value & 0x01) != 0; + bool prevSel = (_prevValue & 0x01) != 0; + bool clr = (value & 0x02) != 0; + bool prevClr = (_prevValue & 0x02) != 0; + + if(!clr && !prevSel && sel) { + _index = (_index + 1) % 5; + } + + if(sel && !prevClr && clr) { + _index = 0; + } + + _prevValue = value; +} diff --git a/Core/PCE/Input/PceTurboTap.h b/Core/PCE/Input/PceTurboTap.h new file mode 100644 index 00000000..f242159a --- /dev/null +++ b/Core/PCE/Input/PceTurboTap.h @@ -0,0 +1,19 @@ +#pragma once +#include "stdafx.h" +#include "Shared/BaseControlDevice.h" +#include "Shared/ControllerHub.h" + +class Emulator; + +class PceTurboTap : public ControllerHub<5> +{ +private: + uint8_t _index = 0; + uint8_t _prevValue = 0; + +public: + PceTurboTap(Emulator* emu, uint8_t port, ControllerConfig controllers[]); + + uint8_t ReadRam(uint16_t addr) override; + void WriteRam(uint16_t addr, uint8_t value) override; +}; \ No newline at end of file diff --git a/Core/PCE/PceControlManager.cpp b/Core/PCE/PceControlManager.cpp index d0c667df..69a59782 100644 --- a/Core/PCE/PceControlManager.cpp +++ b/Core/PCE/PceControlManager.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "PCE/PceControlManager.h" #include "PCE/Input/PceController.h" +#include "PCE/Input/PceTurboTap.h" +#include "PCE/Input/PceAvenuePad6.h" #include "Shared/EmuSettings.h" #include "Shared/BaseControlDevice.h" #include "Shared/Emulator.h" @@ -16,9 +18,24 @@ PceControlManagerState& PceControlManager::GetState() shared_ptr PceControlManager::CreateControllerDevice(ControllerType type, uint8_t port) { - //TODO - GameboyConfig cfg = _emu->GetSettings()->GetGameboyConfig(); - shared_ptr device(new PceController(_emu, port, cfg.Controller.Keys)); + PcEngineConfig& cfg = _emu->GetSettings()->GetPcEngineConfig(); + shared_ptr device; + + switch(type) { + default: + case ControllerType::None: break; + + case ControllerType::PceController: device.reset(new PceController(_emu, port, cfg.Port1.Keys)); break; + case ControllerType::PceAvenuePad6: device.reset(new PceAvenuePad6(_emu, port, cfg.Port1.Keys)); break; + + case ControllerType::PceTurboTap: { + ControllerConfig controllers[5]; + std::copy(cfg.Port1SubPorts, cfg.Port1SubPorts + 5, controllers); + controllers[0].Keys = cfg.Port1.Keys; + device.reset(new PceTurboTap(_emu, port, controllers)); + break; + } + } return device; } @@ -45,7 +62,7 @@ void PceControlManager::WriteInputPort(uint8_t value) void PceControlManager::UpdateControlDevices() { - GameboyConfig cfg = _emu->GetSettings()->GetGameboyConfig(); + PcEngineConfig& cfg = _emu->GetSettings()->GetPcEngineConfig(); if(_emu->GetSettings()->IsEqual(_prevConfig, cfg) && _controlDevices.size() > 0) { //Do nothing if configuration is unchanged return; @@ -55,7 +72,7 @@ void PceControlManager::UpdateControlDevices() ClearDevices(); - shared_ptr device(CreateControllerDevice(ControllerType::GameboyController, 0)); + shared_ptr device(CreateControllerDevice(cfg.Port1.Type, 0)); if(device) { RegisterControlDevice(device); } diff --git a/Core/PCE/PceControlManager.h b/Core/PCE/PceControlManager.h index c5228e92..2d2f5cd0 100644 --- a/Core/PCE/PceControlManager.h +++ b/Core/PCE/PceControlManager.h @@ -10,7 +10,7 @@ class PceControlManager : public BaseControlManager { private: PceControlManagerState _state = {}; - GameboyConfig _prevConfig = {}; + PcEngineConfig _prevConfig = {}; public: PceControlManager(Emulator* emu); diff --git a/Core/PCE/PceMemoryManager.h b/Core/PCE/PceMemoryManager.h index 4f041790..3431b242 100644 --- a/Core/PCE/PceMemoryManager.h +++ b/Core/PCE/PceMemoryManager.h @@ -69,22 +69,20 @@ public: memcpy(_prgRom, romData.data(), _prgRomSize); - //TODO random - memset(_workRam, 0, _workRamSize); _emu->GetSettings()->InitializeRam(_workRam, _workRamSize); if(_cdrom) { _saveRam = new uint8_t[_saveRamSize]; _cdromRam = new uint8_t[_cdromRamSize]; _cardRam = new uint8_t[_cardRamSize]; - //TODO random - memset(_saveRam, 0, _saveRamSize); - memset(_cdromRam, 0, _cdromRamSize); - memset(_cardRam, 0, _cardRamSize); + _emu->GetSettings()->InitializeRam(_saveRam, _saveRamSize); + _emu->GetSettings()->InitializeRam(_cdromRam, _cdromRamSize); + _emu->GetSettings()->InitializeRam(_cardRam, _cardRamSize); _emu->RegisterMemory(MemoryType::PceSaveRam, _saveRam, _saveRamSize); _emu->RegisterMemory(MemoryType::PceCdromRam, _cdromRam, _cdromRamSize); _emu->RegisterMemory(MemoryType::PceCardRam, _cardRam, _cardRamSize); + //TODO improve this _saveRam[0] = 0x48; _saveRam[1] = 0x55; _saveRam[2] = 0x42; diff --git a/Core/PCE/PcePpu.cpp b/Core/PCE/PcePpu.cpp index d53292b1..0c553add 100644 --- a/Core/PCE/PcePpu.cpp +++ b/Core/PCE/PcePpu.cpp @@ -40,7 +40,6 @@ PcePpu::PcePpu(Emulator* emu, PceConsole* console) _state.HorizDisplayWidth = 0x1F; _state.VertDisplayWidth = 239; _state.VceScanlineCount = 262; - UpdateFrameTimings(); _emu->RegisterMemory(MemoryType::PceVideoRam, _vram, 0x8000 * sizeof(uint16_t)); _emu->RegisterMemory(MemoryType::PcePaletteRam, _paletteRam, 0x200 * sizeof(uint16_t)); @@ -703,7 +702,6 @@ void PcePpu::DrawScanline() if(_state.HClock == 1365) { uint16_t row = _state.Scanline - 14; - uint32_t width = PceConstants::GetRowWidth(_state.VceClockDivider); if(row == 0) { _currentOutBuffer = _currentOutBuffer == _outBuffer[0] ? _outBuffer[1] : _outBuffer[0]; @@ -732,15 +730,7 @@ void PcePpu::SendFrame() _emu->ProcessEndOfFrame(); _console->GetControlManager()->UpdateInputState(); -} - -void PcePpu::UpdateFrameTimings() -{ - _state.DisplayStart = _state.VertDisplayStart + _state.VertSyncWidth; - _state.VerticalBlankScanline = _state.DisplayStart + _state.VertDisplayWidth + 1; - if(_state.VerticalBlankScanline > 261) { - _state.VerticalBlankScanline = 261; - } + _console->GetControlManager()->UpdateControlDevices(); } void PcePpu::LoadReadBuffer() @@ -927,7 +917,6 @@ void PcePpu::WriteVdc(uint16_t addr, uint8_t value) _state.HorizDisplayEnd = value & 0x7F; } else { _state.HorizDisplayWidth = value & 0x7F; - UpdateFrameTimings(); } break; @@ -937,12 +926,10 @@ void PcePpu::WriteVdc(uint16_t addr, uint8_t value) } else { _state.VertSyncWidth = value & 0x1F; } - UpdateFrameTimings(); break; case 0x0D: UpdateReg<0x1FF>(_state.VertDisplayWidth, value, msb); - UpdateFrameTimings(); break; case 0x0E: @@ -1036,7 +1023,6 @@ void PcePpu::WriteVce(uint16_t addr, uint8_t value) case 1: _state.VceClockDivider = 3; break; case 2: case 3: _state.VceClockDivider = 2; break; } - UpdateFrameTimings(); //LogDebug("[Debug] VCE Clock divider: " + HexUtilities::ToHex(_state.VceClockDivider) + " SL: " + std::to_string(_state.Scanline)); break; diff --git a/Core/PCE/PcePpu.h b/Core/PCE/PcePpu.h index da71136d..c3523a16 100644 --- a/Core/PCE/PcePpu.h +++ b/Core/PCE/PcePpu.h @@ -120,13 +120,11 @@ private: void DrawScanline(); void SendFrame(); - void UpdateFrameTimings(); - uint16_t DotsToClocks(int dots); void TriggerHdsIrqs(); __declspec(noinline) void IncrementRcrCounter(); - void IncScrollY(); + __declspec(noinline) void IncScrollY(); __declspec(noinline) void ProcessEndOfScanline(); __declspec(noinline) void ProcessEndOfVisibleFrame(); __declspec(noinline) void ProcessSatbTransfer(); @@ -135,14 +133,14 @@ private: __declspec(noinline) void ProcessVdcEvents(); __declspec(noinline) void ProcessEvent(); - void ProcessHorizontalSyncStart(); + __declspec(noinline) void ProcessHorizontalSyncStart(); __forceinline uint8_t GetTilePixelColor(const uint16_t chrData[2], const uint8_t shift); __forceinline uint8_t GetSpritePixelColor(const uint16_t chrData[4], const uint8_t shift); - void ProcessSpriteEvaluation(); - void LoadBackgroundTiles(); - void LoadSpriteTiles(); + __declspec(noinline) void ProcessSpriteEvaluation(); + __declspec(noinline) void LoadBackgroundTiles(); + __declspec(noinline) void LoadSpriteTiles(); void WaitForVramAccess(); bool IsVramAccessBlocked(); diff --git a/Core/PCE/PcePsg.cpp b/Core/PCE/PcePsg.cpp index e69b4d86..c251f503 100644 --- a/Core/PCE/PcePsg.cpp +++ b/Core/PCE/PcePsg.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "PCE/PcePsg.h" #include "Shared/Emulator.h" +#include "Shared/EmuSettings.h" #include "Shared/MessageManager.h" #include "Shared/Audio/SoundMixer.h" #include "Utilities/Audio/blip_buf.h" @@ -66,6 +67,7 @@ void PcePsg::Run() { uint64_t clock = _emu->GetMasterClock(); uint32_t clocksToRun = clock - _lastClock; + PcEngineConfig& cfg = _emu->GetSettings()->GetPcEngineConfig(); while(clocksToRun >= 6) { uint32_t minTimer = clocksToRun / 6; for(int i = 0; i < 6; i++) { @@ -80,8 +82,8 @@ void PcePsg::Run() for(int i = 0; i < 6; i++) { PcePsgChannel& ch = _channels[i]; ch.Run(minTimer); - leftOutput += ch.GetOutput(true, _state.LeftVolume); - rightOutput += ch.GetOutput(false, _state.RightVolume); + leftOutput += (int32_t)ch.GetOutput(true, _state.LeftVolume) * (int32_t)cfg.ChannelVol[i] / 100; + rightOutput += (int32_t)ch.GetOutput(false, _state.RightVolume) * (int32_t)cfg.ChannelVol[i] / 100; } if(_prevLeftOutput != leftOutput) { diff --git a/Core/PCE/PceTypes.h b/Core/PCE/PceTypes.h index 3e3c8d87..87ca2a35 100644 --- a/Core/PCE/PceTypes.h +++ b/Core/PCE/PceTypes.h @@ -62,12 +62,7 @@ struct PcePpuState : public BaseState uint16_t HClock; uint16_t Scanline; - uint16_t DisplayCounter; uint16_t VceScanlineCount; - uint16_t DisplayStart; - uint16_t VerticalBlankScanline; - uint16_t LatchScrollCycle; - uint16_t RcrTriggerCycle; uint16_t RcrCounter; uint8_t CurrentReg; diff --git a/Core/Shared/ControllerHub.h b/Core/Shared/ControllerHub.h index c4471606..17035ab6 100644 --- a/Core/Shared/ControllerHub.h +++ b/Core/Shared/ControllerHub.h @@ -6,6 +6,7 @@ #include "SNES/Input/SnesController.h" #include "SNES/Input/SnesMouse.h" #include "NES/Input/NesController.h" +#include "PCE/Input/PceController.h" #include "Utilities/Serializer.h" #include "Utilities/StringUtilities.h" @@ -60,6 +61,10 @@ public: case ControllerType::SnesMouse: _ports[i].reset(new SnesMouse(emu, 0)); break; + + case ControllerType::PceController: + _ports[i].reset(new PceController(emu, 0, controllers[i].Keys)); + break; } } @@ -126,9 +131,13 @@ public: int pos = 0; for(int i = 0; i < HubPortCount; i++) { - if(_ports[i]) { + if(_ports[i] && pos < data.size()) { int length = data[pos++]; + if(pos + length > data.size()) { + break; + } + ControlDeviceState portState; portState.State.insert(portState.State.begin(), data.begin() + pos, data.begin() + pos + length); _ports[i]->SetRawState(portState); diff --git a/Core/Shared/EmuSettings.cpp b/Core/Shared/EmuSettings.cpp index c99e2708..34a0cca2 100644 --- a/Core/Shared/EmuSettings.cpp +++ b/Core/Shared/EmuSettings.cpp @@ -169,6 +169,16 @@ GameboyConfig& EmuSettings::GetGameboyConfig() return _gameboy; } +void EmuSettings::SetPcEngineConfig(PcEngineConfig& config) +{ + _pce = config; +} + +PcEngineConfig& EmuSettings::GetPcEngineConfig() +{ + return _pce; +} + void EmuSettings::SetPreferences(PreferencesConfig& config) { ProcessString(_saveFolder, &config.SaveFolderOverride); @@ -397,6 +407,8 @@ void EmuSettings::InitializeRam(void* data, uint32_t length) case ConsoleType::GameboyColor: state = _gameboy.RamPowerOnState; break; + + case ConsoleType::PcEngine: state = _pce.RamPowerOnState; break; } switch(state) { diff --git a/Core/Shared/EmuSettings.h b/Core/Shared/EmuSettings.h index 437066ce..321ce676 100644 --- a/Core/Shared/EmuSettings.h +++ b/Core/Shared/EmuSettings.h @@ -22,6 +22,7 @@ private: AudioPlayerConfig _audioPlayer; SnesConfig _snes; NesConfig _nes; + PcEngineConfig _pce; atomic _flags; atomic _debuggerFlags; @@ -70,6 +71,9 @@ public: void SetGameboyConfig(GameboyConfig& config); GameboyConfig& GetGameboyConfig(); + void SetPcEngineConfig(PcEngineConfig& config); + PcEngineConfig& GetPcEngineConfig(); + void SetPreferences(PreferencesConfig& config); PreferencesConfig& GetPreferences(); diff --git a/Core/Shared/SettingTypes.h b/Core/Shared/SettingTypes.h index 8dc25933..531ac2d3 100644 --- a/Core/Shared/SettingTypes.h +++ b/Core/Shared/SettingTypes.h @@ -206,6 +206,11 @@ enum class ControllerType //Game Boy GameboyController, + + //PC Engine + PceController, + PceTurboTap, + PceAvenuePad6, }; struct KeyMapping @@ -364,6 +369,16 @@ struct GameboyConfig uint32_t WaveVol = 100; }; +struct PcEngineConfig +{ + ControllerConfig Port1; + ControllerConfig Port1SubPorts[5]; + + RamState RamPowerOnState = RamState::Random; + + uint32_t ChannelVol[6] = { 100, 100, 100, 100, 100, 100 }; +}; + struct SnesConfig { ControllerConfig Port1; diff --git a/InteropDLL/ConfigApiWrapper.cpp b/InteropDLL/ConfigApiWrapper.cpp index a7479024..e2575c64 100644 --- a/InteropDLL/ConfigApiWrapper.cpp +++ b/InteropDLL/ConfigApiWrapper.cpp @@ -36,6 +36,11 @@ extern "C" { _emu->GetSettings()->SetGameboyConfig(config); } + DllExport void __stdcall SetPcEngineConfig(PcEngineConfig config) + { + _emu->GetSettings()->SetPcEngineConfig(config); + } + DllExport void __stdcall SetNesConfig(NesConfig config) { _emu->GetSettings()->SetNesConfig(config); diff --git a/NewUI/Assets/PceIcon.png b/NewUI/Assets/PceIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..fbbb94161cbfc84a0b04f2446595b000869c3a08 GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&C3 z=qM&(QM9wM`&J`JOJ0Ar}5uFCFAOpuod=LB`AbrOvv^KV?)G@9>mb(q?i* z>4vkmjlksp{!ZsAPr3Vhbt*5N;<_eDc(+Bv%utc88)phuEEiLF)El3*Xzzvvyle0E zi3tQgojxzak^8&Xo85c&hd*Fnyd~k-*YE$T8T`DzhH{pyPV{47U|{fc^>bP0l+XkK D=f_&Z literal 0 HcmV?d00001 diff --git a/NewUI/Config/Configuration.cs b/NewUI/Config/Configuration.cs index 9847cebd..e9fe4e2e 100644 --- a/NewUI/Config/Configuration.cs +++ b/NewUI/Config/Configuration.cs @@ -26,6 +26,7 @@ namespace Mesen.Config [Reactive] public SnesConfig Snes { get; set; } = new(); [Reactive] public NesConfig Nes { get; set; } = new(); [Reactive] public GameboyConfig Gameboy { get; set; } = new(); + [Reactive] public PcEngineConfig PcEngine { get; set; } = new(); [Reactive] public PreferencesConfig Preferences { get; set; } = new(); [Reactive] public AudioPlayerConfig AudioPlayer { get; set; } = new(); [Reactive] public DebugConfig Debug { get; set; } = new(); @@ -61,6 +62,7 @@ namespace Mesen.Config Input.ApplyConfig(); Emulation.ApplyConfig(); Gameboy.ApplyConfig(); + PcEngine.ApplyConfig(); Nes.ApplyConfig(); Snes.ApplyConfig(); Preferences.ApplyConfig(); diff --git a/NewUI/Config/InputConfig.cs b/NewUI/Config/InputConfig.cs index b7754f79..7620acb2 100644 --- a/NewUI/Config/InputConfig.cs +++ b/NewUI/Config/InputConfig.cs @@ -108,23 +108,15 @@ namespace Mesen.Config public virtual void SetDefaultKeys(ControllerType type, KeyPresetType? preset = null) { - switch(type) { - case ControllerType.NesController: - case ControllerType.FamicomController: - case ControllerType.FamicomControllerP2: - case ControllerType.HoriTrack: - case ControllerType.BandaiHyperShot: - case ControllerType.SnesController: - case ControllerType.GameboyController: - switch(preset) { - case KeyPresetType.WasdKeys: KeyPresets.ApplyWasdLayout(this, type); break; - case KeyPresetType.ArrowKeys: KeyPresets.ApplyArrowLayout(this, type); break; - case KeyPresetType.XboxP1: KeyPresets.ApplyXboxLayout(this, 0, type); break; - case KeyPresetType.XboxP2: KeyPresets.ApplyXboxLayout(this, 1, type); break; - case KeyPresetType.Ps4P1: KeyPresets.ApplyPs4Layout(this, 0, type); break; - case KeyPresetType.Ps4P2: KeyPresets.ApplyPs4Layout(this, 1, type); break; - } - break; + if(type.HasPresets()) { + switch(preset) { + case KeyPresetType.WasdKeys: KeyPresets.ApplyWasdLayout(this, type); break; + case KeyPresetType.ArrowKeys: KeyPresets.ApplyArrowLayout(this, type); break; + case KeyPresetType.XboxP1: KeyPresets.ApplyXboxLayout(this, 0, type); break; + case KeyPresetType.XboxP2: KeyPresets.ApplyXboxLayout(this, 1, type); break; + case KeyPresetType.Ps4P1: KeyPresets.ApplyPs4Layout(this, 0, type); break; + case KeyPresetType.Ps4P2: KeyPresets.ApplyPs4Layout(this, 1, type); break; + } } } @@ -301,6 +293,11 @@ namespace Mesen.Config //Game Boy GameboyController, + + //PC Engine + PceController, + PceTurboTap, + PceAvenuePad6 } public static class ControllerTypeExtensions @@ -313,6 +310,8 @@ namespace Mesen.Config case ControllerType.FamicomController: case ControllerType.FamicomControllerP2: case ControllerType.GameboyController: + case ControllerType.PceController: + case ControllerType.PceAvenuePad6: case ControllerType.HoriTrack: case ControllerType.BandaiHyperShot: return true; @@ -329,6 +328,8 @@ namespace Mesen.Config case ControllerType.FamicomController: case ControllerType.FamicomControllerP2: case ControllerType.GameboyController: + case ControllerType.PceController: + case ControllerType.PceAvenuePad6: case ControllerType.Pachinko: case ControllerType.HoriTrack: case ControllerType.BandaiHyperShot: @@ -357,6 +358,8 @@ namespace Mesen.Config case ControllerType.JissenMahjong: case ControllerType.ExcitingBoxing: case ControllerType.GameboyController: + case ControllerType.PceController: + case ControllerType.PceAvenuePad6: case ControllerType.HoriTrack: case ControllerType.KonamiHyperShot: case ControllerType.BandaiHyperShot: diff --git a/NewUI/Config/KeyPresets.cs b/NewUI/Config/KeyPresets.cs index 7167bc21..a7683343 100644 --- a/NewUI/Config/KeyPresets.cs +++ b/NewUI/Config/KeyPresets.cs @@ -18,6 +18,13 @@ namespace Mesen.Config m.R = InputApi.GetKeyCode("I"); m.Select = InputApi.GetKeyCode("O"); m.Start = InputApi.GetKeyCode("L"); + } else if(type == ControllerType.PceAvenuePad6) { + m.X = InputApi.GetKeyCode("H"); + m.Y = InputApi.GetKeyCode("Y"); + m.L = InputApi.GetKeyCode("U"); + m.R = InputApi.GetKeyCode("I"); + m.Select = InputApi.GetKeyCode("N"); + m.Start = InputApi.GetKeyCode("M"); } else { m.TurboA = InputApi.GetKeyCode(";"); m.TurboB = InputApi.GetKeyCode("M"); @@ -42,6 +49,15 @@ namespace Mesen.Config m.R = InputApi.GetKeyCode("W"); m.Select = InputApi.GetKeyCode("E"); m.Start = InputApi.GetKeyCode("D"); + } else if(type == ControllerType.PceAvenuePad6) { + m.Y = InputApi.GetKeyCode("A"); + m.L = InputApi.GetKeyCode("S"); + m.R = InputApi.GetKeyCode("D"); + m.A = InputApi.GetKeyCode("Z"); + m.B = InputApi.GetKeyCode("X"); + m.X = InputApi.GetKeyCode("C"); + m.Select = InputApi.GetKeyCode("Q"); + m.Start = InputApi.GetKeyCode("W"); } else { m.TurboA = InputApi.GetKeyCode("X"); m.TurboB = InputApi.GetKeyCode("Z"); @@ -59,7 +75,7 @@ namespace Mesen.Config string prefix = "Pad" + (player + 1).ToString() + " "; m.A = InputApi.GetKeyCode(prefix + "B"); m.B = InputApi.GetKeyCode(prefix + "A"); - if(type == ControllerType.SnesController) { + if(type == ControllerType.SnesController || type == ControllerType.PceAvenuePad6) { m.X = InputApi.GetKeyCode(prefix + "Y"); m.Y = InputApi.GetKeyCode(prefix + "X"); m.L = InputApi.GetKeyCode(prefix + "L1"); @@ -81,7 +97,7 @@ namespace Mesen.Config string prefix = "Joy" + (player + 1).ToString() + " "; m.A = InputApi.GetKeyCode(prefix + "But3"); m.B = InputApi.GetKeyCode(prefix + "But2"); - if(type == ControllerType.SnesController) { + if(type == ControllerType.SnesController || type == ControllerType.PceAvenuePad6) { m.X = InputApi.GetKeyCode(prefix + "But4"); m.Y = InputApi.GetKeyCode(prefix + "But1"); m.L = InputApi.GetKeyCode(prefix + "But5"); diff --git a/NewUI/Config/PcEngineConfig.cs b/NewUI/Config/PcEngineConfig.cs new file mode 100644 index 00000000..7880e23e --- /dev/null +++ b/NewUI/Config/PcEngineConfig.cs @@ -0,0 +1,113 @@ +using Mesen.Interop; +using ReactiveUI.Fody.Helpers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Mesen.Config +{ + public class PcEngineConfig : BaseConfig + { + [Reactive] public ControllerConfig Port1 { get; set; } = new(); + + [Reactive] public ControllerConfig Port1A { get; set; } = new(); + [Reactive] public ControllerConfig Port1B { get; set; } = new(); + [Reactive] public ControllerConfig Port1C { get; set; } = new(); + [Reactive] public ControllerConfig Port1D { get; set; } = new(); + [Reactive] public ControllerConfig Port1E { get; set; } = new(); + + [Reactive] public RamState RamPowerOnState { get; set; } = RamState.Random; + + [Reactive] public UInt32 Channel1Vol { get; set; } = 100; + [Reactive] public UInt32 Channel2Vol { get; set; } = 100; + [Reactive] public UInt32 Channel3Vol { get; set; } = 100; + [Reactive] public UInt32 Channel4Vol { get; set; } = 100; + [Reactive] public UInt32 Channel5Vol { get; set; } = 100; + [Reactive] public UInt32 Channel6Vol { get; set; } = 100; + + public void ApplyConfig() + { + ConfigApi.SetPcEngineConfig(new InteropPcEngineConfig() { + Port1 = Port1.ToInterop(), + Port1A = Port1A.ToInterop(), + Port1B = Port1B.ToInterop(), + Port1C = Port1C.ToInterop(), + Port1D = Port1D.ToInterop(), + Port1E = Port1E.ToInterop(), + + RamPowerOnState = RamPowerOnState, + + Channel1Vol = Channel1Vol, + Channel2Vol = Channel2Vol, + Channel3Vol = Channel3Vol, + Channel4Vol = Channel4Vol, + Channel5Vol = Channel5Vol, + Channel6Vol = Channel6Vol, + }); + } + + internal void InitializeDefaults(DefaultKeyMappingType defaultMappings) + { + List mappings = new List(); + if(defaultMappings.HasFlag(DefaultKeyMappingType.Xbox)) { + KeyMapping mapping = new(); + KeyPresets.ApplyXboxLayout(mapping, 0, ControllerType.PceController); + mappings.Add(mapping); + } + if(defaultMappings.HasFlag(DefaultKeyMappingType.Ps4)) { + KeyMapping mapping = new(); + KeyPresets.ApplyPs4Layout(mapping, 0, ControllerType.PceController); + mappings.Add(mapping); + } + if(defaultMappings.HasFlag(DefaultKeyMappingType.WasdKeys)) { + KeyMapping mapping = new(); + KeyPresets.ApplyWasdLayout(mapping, ControllerType.PceController); + mappings.Add(mapping); + } + if(defaultMappings.HasFlag(DefaultKeyMappingType.ArrowKeys)) { + KeyMapping mapping = new(); + KeyPresets.ApplyArrowLayout(mapping, ControllerType.PceController); + mappings.Add(mapping); + } + + Port1.Type = ControllerType.PceController; + Port1.TurboSpeed = 2; + if(mappings.Count > 0) { + Port1.Mapping1 = mappings[0]; + if(mappings.Count > 1) { + Port1.Mapping2 = mappings[1]; + if(mappings.Count > 2) { + Port1.Mapping3 = mappings[2]; + if(mappings.Count > 3) { + Port1.Mapping4 = mappings[3]; + } + } + } + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct InteropPcEngineConfig + { + public InteropControllerConfig Port1; + + public InteropControllerConfig Port1A; + public InteropControllerConfig Port1B; + public InteropControllerConfig Port1C; + public InteropControllerConfig Port1D; + public InteropControllerConfig Port1E; + + public RamState RamPowerOnState; + + public UInt32 Channel1Vol; + public UInt32 Channel2Vol; + public UInt32 Channel3Vol; + public UInt32 Channel4Vol; + public UInt32 Channel5Vol; + public UInt32 Channel6Vol; + } +} diff --git a/NewUI/Controls/ControllerButton.axaml b/NewUI/Controls/ControllerButton.axaml new file mode 100644 index 00000000..257ec7b5 --- /dev/null +++ b/NewUI/Controls/ControllerButton.axaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/NewUI/Controls/ControllerButton.axaml.cs b/NewUI/Controls/ControllerButton.axaml.cs new file mode 100644 index 00000000..8297d278 --- /dev/null +++ b/NewUI/Controls/ControllerButton.axaml.cs @@ -0,0 +1,50 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.Media; +using System; + +namespace Mesen.Controls +{ + public class ControllerButton : UserControl + { + public static readonly StyledProperty KeyBindingProperty = AvaloniaProperty.Register(nameof(KeyBinding), 0, false, Avalonia.Data.BindingMode.TwoWay); + public static readonly StyledProperty TurboKeyBindingProperty = AvaloniaProperty.Register(nameof(TurboKeyBinding), 0, false, Avalonia.Data.BindingMode.TwoWay); + public static readonly StyledProperty LabelProperty = AvaloniaProperty.Register(nameof(Label)); + public static readonly StyledProperty HasTurboProperty = AvaloniaProperty.Register(nameof(HasTurbo), true); + + public UInt32 KeyBinding + { + get { return GetValue(KeyBindingProperty); } + set { SetValue(KeyBindingProperty, value); } + } + + public UInt32 TurboKeyBinding + { + get { return GetValue(TurboKeyBindingProperty); } + set { SetValue(TurboKeyBindingProperty, value); } + } + + public string Label + { + get { return GetValue(LabelProperty); } + set { SetValue(LabelProperty, value); } + } + + public bool HasTurbo + { + get { return GetValue(HasTurboProperty); } + set { SetValue(HasTurboProperty, value); } + } + + public ControllerButton() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/NewUI/Controls/SystemSpecificSettings.axaml b/NewUI/Controls/SystemSpecificSettings.axaml index f6c260e5..4c8893ce 100644 --- a/NewUI/Controls/SystemSpecificSettings.axaml +++ b/NewUI/Controls/SystemSpecificSettings.axaml @@ -15,6 +15,7 @@ + \ No newline at end of file diff --git a/NewUI/Controls/SystemSpecificSettings.axaml.cs b/NewUI/Controls/SystemSpecificSettings.axaml.cs index 61838f7e..ccf97af7 100644 --- a/NewUI/Controls/SystemSpecificSettings.axaml.cs +++ b/NewUI/Controls/SystemSpecificSettings.axaml.cs @@ -49,6 +49,11 @@ namespace Mesen.Controls NavigateTo(ConfigWindowTab.Gameboy); } + private void OnClickPcEngine(object sender, RoutedEventArgs e) + { + NavigateTo(ConfigWindowTab.PcEngine); + } + private void NavigateTo(ConfigWindowTab console) { if(VisualRoot is ConfigWindow wnd && wnd.DataContext is ConfigViewModel cfg) { @@ -87,6 +92,17 @@ namespace Mesen.Controls }; } break; + + case ConfigWindowTab.PcEngine: + if(cfg.PcEngine != null) { + cfg.PcEngine.SelectedTab = ConfigType switch { + ConfigType.Audio => PceConfigTab.Audio, + ConfigType.Emulation => PceConfigTab.Emulation, + ConfigType.Input => PceConfigTab.Input, + _ or ConfigType.Video => PceConfigTab.Video, + }; + } + break; } } } diff --git a/NewUI/Debugger/StatusViews/PceStatusViewModel.cs b/NewUI/Debugger/StatusViews/PceStatusViewModel.cs index bf8d1483..e8d8d552 100644 --- a/NewUI/Debugger/StatusViews/PceStatusViewModel.cs +++ b/NewUI/Debugger/StatusViews/PceStatusViewModel.cs @@ -76,7 +76,7 @@ namespace Mesen.Debugger.StatusViews } StackPreview = sb.ToString(); - Cycle = ppu.Cycle; + Cycle = ppu.HClock; Scanline = ppu.Scanline; FrameCount = ppu.FrameCount; } @@ -93,7 +93,7 @@ namespace Mesen.Debugger.StatusViews cpu.PC = RegPC; cpu.PS = RegPS; - ppu.Cycle = Cycle; + ppu.HClock = Cycle; ppu.Scanline = Scanline; DebugApi.SetCpuState(cpu, CpuType.Pce); diff --git a/NewUI/Debugger/Utilities/ContextMenuAction.cs b/NewUI/Debugger/Utilities/ContextMenuAction.cs index aaa7c36f..1887dd71 100644 --- a/NewUI/Debugger/Utilities/ContextMenuAction.cs +++ b/NewUI/Debugger/Utilities/ContextMenuAction.cs @@ -550,6 +550,8 @@ namespace Mesen.Debugger.Utilities Snes, [IconFile("GameboyIcon")] Gameboy, + [IconFile("PceIcon")] + PcEngine, [IconFile("MediaPause")] Pause, [IconFile("MediaStop")] diff --git a/NewUI/Debugger/ViewModels/RegisterViewerWindowViewModel.cs b/NewUI/Debugger/ViewModels/RegisterViewerWindowViewModel.cs index 690f939f..bbae932e 100644 --- a/NewUI/Debugger/ViewModels/RegisterViewerWindowViewModel.cs +++ b/NewUI/Debugger/ViewModels/RegisterViewerWindowViewModel.cs @@ -1139,7 +1139,7 @@ namespace Mesen.Debugger.ViewModels List entries = new List() { new RegEntry("", "State", null), - new RegEntry("", "Cycle (H)", ppu.Cycle, Format.X16), + new RegEntry("", "HClock (H)", ppu.HClock, Format.X16), new RegEntry("", "Scanline (V)", ppu.Scanline, Format.X16), new RegEntry("", "Frame Number", ppu.FrameCount), diff --git a/NewUI/Interop/ConfigApi.cs b/NewUI/Interop/ConfigApi.cs index 5d4a334c..30a3559c 100644 --- a/NewUI/Interop/ConfigApi.cs +++ b/NewUI/Interop/ConfigApi.cs @@ -21,6 +21,7 @@ namespace Mesen.Interop [DllImport(DllPath)] public static extern void SetInputConfig(InteropInputConfig config); [DllImport(DllPath)] public static extern void SetEmulationConfig(InteropEmulationConfig config); [DllImport(DllPath)] public static extern void SetGameboyConfig(InteropGameboyConfig config); + [DllImport(DllPath)] public static extern void SetPcEngineConfig(InteropPcEngineConfig config); [DllImport(DllPath)] public static extern void SetNesConfig(InteropNesConfig config); [DllImport(DllPath)] public static extern void SetSnesConfig(InteropSnesConfig config); diff --git a/NewUI/Interop/DebugState.cs b/NewUI/Interop/DebugState.cs index 77ad9c40..04ef6866 100644 --- a/NewUI/Interop/DebugState.cs +++ b/NewUI/Interop/DebugState.cs @@ -1305,14 +1305,10 @@ namespace Mesen.Interop public struct PcePpuState : BaseState { public UInt32 FrameCount; - public UInt16 Cycle; + + public UInt16 HClock; public UInt16 Scanline; - public UInt16 DisplayCounter; public UInt16 VceScanlineCount; - public UInt16 DisplayStart; - public UInt16 VerticalBlankScanline; - public UInt16 LatchScrollCycle; - public UInt16 RcrTriggerCycle; public UInt16 RcrCounter; public byte CurrentReg; diff --git a/NewUI/Localization/resources.en.xml b/NewUI/Localization/resources.en.xml index 6dba3931..7e0aad4d 100644 --- a/NewUI/Localization/resources.en.xml +++ b/NewUI/Localization/resources.en.xml @@ -23,7 +23,7 @@
Close
-
+ General Mute sound when in background @@ -58,7 +58,7 @@ Equalizer Enable Equalizer
-
+ Controllers General Light detection radius for light guns: @@ -87,7 +87,7 @@ Expansion device:
-
+ Port 1: Port 2: Port 1: @@ -135,7 +135,7 @@ Bottom Right
-
+ General Enable integer FPS mode (e.g: run at 60 fps instead of 60.1) Enable vertical sync @@ -188,7 +188,7 @@ Advanced Screen Rotation:
-
+ General % (0 = Maximum speed) Emulation Speed: @@ -331,7 +331,7 @@ Console model: Allow invalid input (e.g Down + Up or Left + Right at the same time)
-
+ General Model Use Super Game Boy 2 timings and behavior @@ -360,6 +360,34 @@ Player 1 Setup
+ +
+ General + Video + + Emulation + Recommended settings for developers (homebrew / ROM hacking) + Default power on state for RAM: + + Input + + Audio + Volume +
+ +
+ Controllers + Turbo Tap Configuration + + Setup + Controller: + Port 1: + Port 2: + Port 3: + Port 4: + Port 5: +
+
Warning: Your current configuration contains conflicting key bindings. If this is not intentional, please review and correct your key bindings. Action @@ -381,6 +409,7 @@ NES SNES Game Boy + PC Engine Preferences Open Mesen folder @@ -390,7 +419,7 @@ Cancel
-
+ General Display Language: Only allow one instance of Mesen at a time @@ -1355,6 +1384,9 @@ Battle Box Gameboy Controller + 2-button Controller + 6-button Controller + Turbo Tap A @@ -2232,6 +2264,7 @@ NES SNES Game Boy + PC Engine Resume Pause diff --git a/NewUI/NewUI.csproj b/NewUI/NewUI.csproj index 0cba8947..d2ac8819 100644 --- a/NewUI/NewUI.csproj +++ b/NewUI/NewUI.csproj @@ -109,6 +109,7 @@ + @@ -194,6 +195,9 @@ ButtonWithIcon.axaml + + ControllerButton.axaml + CodeScrollBar.axaml @@ -365,6 +369,18 @@ MemoryToolsWindow.axaml + + PceAvenuePad6View.axaml + + + PceControllerView.axaml + + + PceInputConfigView.axaml + + + PceConfigView.axaml + InputConfigView.axaml @@ -559,6 +575,7 @@ + diff --git a/NewUI/ViewModels/ConfigViewModel.cs b/NewUI/ViewModels/ConfigViewModel.cs index 2c84ef1b..2a7cb4d6 100644 --- a/NewUI/ViewModels/ConfigViewModel.cs +++ b/NewUI/ViewModels/ConfigViewModel.cs @@ -18,6 +18,7 @@ namespace Mesen.ViewModels [Reactive] public SnesConfigViewModel? Snes { get; set; } [Reactive] public NesConfigViewModel? Nes { get; set; } [Reactive] public GameboyConfigViewModel? Gameboy { get; set; } + [Reactive] public PceConfigViewModel? PcEngine { get; set; } [Reactive] public ConfigWindowTab SelectedIndex { get; set; } @@ -50,6 +51,7 @@ namespace Mesen.ViewModels case ConfigWindowTab.Snes: Snes ??= AddDisposable(new SnesConfigViewModel()); break; case ConfigWindowTab.Gameboy: Gameboy ??= AddDisposable(new GameboyConfigViewModel()); break; + case ConfigWindowTab.PcEngine: PcEngine ??= AddDisposable(new PceConfigViewModel()); break; case ConfigWindowTab.Preferences: Preferences ??= AddDisposable(new PreferencesConfigViewModel()); break; } @@ -72,6 +74,7 @@ namespace Mesen.ViewModels ConfigManager.Config.Nes = Nes?.Config.Clone() ?? ConfigManager.Config.Nes; ConfigManager.Config.Snes = Snes?.Config.Clone() ?? ConfigManager.Config.Snes; ConfigManager.Config.Gameboy = Gameboy?.Config.Clone() ?? ConfigManager.Config.Gameboy; + ConfigManager.Config.PcEngine = PcEngine?.Config.Clone() ?? ConfigManager.Config.PcEngine; ConfigManager.Config.ApplyConfig(); ConfigManager.Config.Save(); @@ -89,7 +92,8 @@ namespace Mesen.ViewModels Nes = 5, Snes = 6, Gameboy = 7, + PcEngine = 8, //separator - Preferences = 9 + Preferences = 10 } } diff --git a/NewUI/ViewModels/MainMenuViewModel.cs b/NewUI/ViewModels/MainMenuViewModel.cs index c8bc44fd..ff672c73 100644 --- a/NewUI/ViewModels/MainMenuViewModel.cs +++ b/NewUI/ViewModels/MainMenuViewModel.cs @@ -407,6 +407,10 @@ namespace Mesen.ViewModels ActionType = ActionType.Gameboy, OnClick = () => OpenConfig(wnd, ConfigWindowTab.Gameboy) }, + new MainMenuAction() { + ActionType = ActionType.PcEngine, + OnClick = () => OpenConfig(wnd, ConfigWindowTab.PcEngine) + }, new ContextMenuSeparator(), diff --git a/NewUI/ViewModels/PceConfigViewModel.cs b/NewUI/ViewModels/PceConfigViewModel.cs new file mode 100644 index 00000000..7d4597a0 --- /dev/null +++ b/NewUI/ViewModels/PceConfigViewModel.cs @@ -0,0 +1,43 @@ +using Avalonia.Controls; +using Mesen.Config; +using Mesen.Utilities; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reactive.Linq; + +namespace Mesen.ViewModels +{ + public class PceConfigViewModel : DisposableViewModel + { + [Reactive] public PcEngineConfig Config { get; set; } + [Reactive] public PceConfigTab SelectedTab { get; set; } = 0; + + public PceInputConfigViewModel Input { get; private set; } + + public PceConfigViewModel() + { + Config = ConfigManager.Config.PcEngine.Clone(); + Input = new PceInputConfigViewModel(Config); + + if(Design.IsDesignMode) { + return; + } + + AddDisposable(Input); + AddDisposable(ReactiveHelper.RegisterRecursiveObserver(Config, (s, e) => { Config.ApplyConfig(); })); + } + } + + public enum PceConfigTab + { + General, + Audio, + Emulation, + Input, + Video + } +} diff --git a/NewUI/ViewModels/PceInputConfigViewModel.cs b/NewUI/ViewModels/PceInputConfigViewModel.cs new file mode 100644 index 00000000..76cba7c2 --- /dev/null +++ b/NewUI/ViewModels/PceInputConfigViewModel.cs @@ -0,0 +1,41 @@ +using Avalonia.Threading; +using Mesen.Config; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using System; +using System.Reactive.Linq; + +namespace Mesen.ViewModels +{ + public class PceInputConfigViewModel : DisposableViewModel + { + [Reactive] public PcEngineConfig Config { get; set; } + [Reactive] public bool HasTurboTap { get; private set; } + + public Enum[] AvailableControllerTypesP1 => new Enum[] { + ControllerType.None, + ControllerType.PceController, + ControllerType.PceAvenuePad6, + ControllerType.PceTurboTap, + }; + + public Enum[] AvailableControllerTypesTurboTap => new Enum[] { + ControllerType.None, + ControllerType.PceController, + }; + + [Obsolete("For designer only")] + public PceInputConfigViewModel() : this(new PcEngineConfig()) { } + + public PceInputConfigViewModel(PcEngineConfig config) + { + Config = config; + + AddDisposable(this.WhenAnyValue(x => x.Config.Port1.Type).Subscribe(t => { + Dispatcher.UIThread.Post(() => { + HasTurboTap = Config.Port1.Type == ControllerType.PceTurboTap; + }); + })); + } + } +} diff --git a/NewUI/Views/ControllerConfigViewLocator.cs b/NewUI/Views/ControllerConfigViewLocator.cs index 3dbbe1f0..d6d0ff4f 100644 --- a/NewUI/Views/ControllerConfigViewLocator.cs +++ b/NewUI/Views/ControllerConfigViewLocator.cs @@ -25,6 +25,8 @@ namespace Mesen.Views ControllerType.BandaiHyperShot => new NesControllerView(), ControllerType.HoriTrack => new NesControllerView(), ControllerType.GameboyController => new NesControllerView(), + ControllerType.PceController => new PceControllerView(), + ControllerType.PceAvenuePad6 => new PceAvenuePad6View(), _ => new DefaultControllerView() }; } diff --git a/NewUI/Views/GameboyConfigView.axaml b/NewUI/Views/GameboyConfigView.axaml index b91e099a..e860d772 100644 --- a/NewUI/Views/GameboyConfigView.axaml +++ b/NewUI/Views/GameboyConfigView.axaml @@ -41,10 +41,19 @@ - - - - + + + + + + + + diff --git a/NewUI/Views/PceAvenuePad6View.axaml b/NewUI/Views/PceAvenuePad6View.axaml new file mode 100644 index 00000000..fa74ca0a --- /dev/null +++ b/NewUI/Views/PceAvenuePad6View.axaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NewUI/Views/PceAvenuePad6View.axaml.cs b/NewUI/Views/PceAvenuePad6View.axaml.cs new file mode 100644 index 00000000..d459f42c --- /dev/null +++ b/NewUI/Views/PceAvenuePad6View.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Mesen.Views +{ + public class PceAvenuePad6View : UserControl + { + public PceAvenuePad6View() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/NewUI/Views/PceConfigView.axaml b/NewUI/Views/PceConfigView.axaml new file mode 100644 index 00000000..17536eb9 --- /dev/null +++ b/NewUI/Views/PceConfigView.axaml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NewUI/Views/PceConfigView.axaml.cs b/NewUI/Views/PceConfigView.axaml.cs new file mode 100644 index 00000000..778052c8 --- /dev/null +++ b/NewUI/Views/PceConfigView.axaml.cs @@ -0,0 +1,30 @@ +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Mesen.Utilities; +using Mesen.Config; +using Mesen.Debugger.Controls; +using Mesen.ViewModels; +using Mesen.Windows; +using System; +using Avalonia.Media; +using System.Threading.Tasks; +using Avalonia.Interactivity; + +namespace Mesen.Views +{ + public class PceConfigView : UserControl + { + public PceConfigView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/NewUI/Views/PceControllerView.axaml b/NewUI/Views/PceControllerView.axaml new file mode 100644 index 00000000..943d6638 --- /dev/null +++ b/NewUI/Views/PceControllerView.axaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NewUI/Views/PceControllerView.axaml.cs b/NewUI/Views/PceControllerView.axaml.cs new file mode 100644 index 00000000..9ce98f42 --- /dev/null +++ b/NewUI/Views/PceControllerView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Mesen.Views +{ + public class PceControllerView : UserControl + { + public PceControllerView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/NewUI/Views/PceInputConfigView.axaml b/NewUI/Views/PceInputConfigView.axaml new file mode 100644 index 00000000..aca550d9 --- /dev/null +++ b/NewUI/Views/PceInputConfigView.axaml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NewUI/Views/PceInputConfigView.axaml.cs b/NewUI/Views/PceInputConfigView.axaml.cs new file mode 100644 index 00000000..29c1dd6d --- /dev/null +++ b/NewUI/Views/PceInputConfigView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Mesen.Views +{ + public class PceInputConfigView : UserControl + { + public PceInputConfigView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/NewUI/Windows/ConfigWindow.axaml b/NewUI/Windows/ConfigWindow.axaml index 13319e4a..24ad0df1 100644 --- a/NewUI/Windows/ConfigWindow.axaml +++ b/NewUI/Windows/ConfigWindow.axaml @@ -41,6 +41,9 @@ + + + @@ -124,6 +127,15 @@ + + + + + + + + +