UI: Added global input options (deadzone, display inputs on screen, etc.)

This commit is contained in:
Sour 2022-03-04 22:08:29 -05:00
parent 9f6841eea5
commit aa6a9699fb
44 changed files with 601 additions and 285 deletions

View file

@ -122,6 +122,7 @@
<ClInclude Include="Shared\Interfaces\stdafx.h" /> <ClInclude Include="Shared\Interfaces\stdafx.h" />
<ClInclude Include="Shared\KeyDefinitions.h" /> <ClInclude Include="Shared\KeyDefinitions.h" />
<ClInclude Include="Shared\Movies\stdafx.h" /> <ClInclude Include="Shared\Movies\stdafx.h" />
<ClInclude Include="Shared\RenderedFrame.h" />
<ClInclude Include="Shared\RomInfo.h" /> <ClInclude Include="Shared\RomInfo.h" />
<ClInclude Include="Shared\stdafx.h" /> <ClInclude Include="Shared\stdafx.h" />
<ClInclude Include="NES\NesDefaultVideoFilter.h" /> <ClInclude Include="NES\NesDefaultVideoFilter.h" />

View file

@ -819,6 +819,7 @@
<ClInclude Include="NES\Debugger\DummyNesCpu.h" /> <ClInclude Include="NES\Debugger\DummyNesCpu.h" />
<ClInclude Include="Gameboy\Debugger\DummyGbCpu.h" /> <ClInclude Include="Gameboy\Debugger\DummyGbCpu.h" />
<ClInclude Include="Debugger\DebuggerFeatures.h" /> <ClInclude Include="Debugger\DebuggerFeatures.h" />
<ClInclude Include="Shared\RenderedFrame.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="SNES\SnesCpu.cpp"> <ClCompile Include="SNES\SnesCpu.cpp">

View file

@ -8,6 +8,8 @@
#include "Shared/Emulator.h" #include "Shared/Emulator.h"
#include "Shared/EmuSettings.h" #include "Shared/EmuSettings.h"
#include "Shared/RewindManager.h" #include "Shared/RewindManager.h"
#include "Shared/Interfaces/IControlManager.h"
#include "Shared/RenderedFrame.h"
#include "Shared/Video/VideoDecoder.h" #include "Shared/Video/VideoDecoder.h"
#include "Shared/NotificationManager.h" #include "Shared/NotificationManager.h"
#include "Shared/MessageManager.h" #include "Shared/MessageManager.h"
@ -650,7 +652,7 @@ void GbPpu::SendFrame()
} }
_isFirstFrame = false; _isFirstFrame = false;
RenderedFrame frame(_currentBuffer, GbConstants::ScreenWidth, GbConstants::ScreenHeight, 1.0, _state.FrameCount); RenderedFrame frame(_currentBuffer, GbConstants::ScreenWidth, GbConstants::ScreenHeight, 1.0, _state.FrameCount, _gameboy->GetControlManager()->GetPortStates());
#ifdef LIBRETRO #ifdef LIBRETRO
_emu->GetVideoDecoder()->UpdateFrame(frame, true, false); _emu->GetVideoDecoder()->UpdateFrame(frame, true, false);
#else #else

View file

@ -3,6 +3,7 @@
#include "Shared/BaseControlDevice.h" #include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h" #include "Shared/Emulator.h"
#include "Shared/EmuSettings.h" #include "Shared/EmuSettings.h"
#include "Shared/InputHud.h"
#include "Utilities/Serializer.h" #include "Utilities/Serializer.h"
class GbController : public BaseControlDevice class GbController : public BaseControlDevice
@ -57,4 +58,23 @@ public:
void WriteRam(uint16_t addr, uint8_t value) override void WriteRam(uint16_t addr, uint8_t value) override
{ {
} }
void DrawController(InputHud& hud)
{
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(30, 7, 3, 3, IsPressed(Buttons::A));
hud.DrawButton(25, 7, 3, 3, IsPressed(Buttons::B));
hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select));
hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start));
hud.DrawNumber(_port + 1, 16, 2);
}
}; };

View file

@ -3,6 +3,7 @@
#include "Shared/BaseControlDevice.h" #include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h" #include "Shared/Emulator.h"
#include "Shared/EmuSettings.h" #include "Shared/EmuSettings.h"
#include "Shared/InputHud.h"
#include "Utilities/Serializer.h" #include "Utilities/Serializer.h"
class NesController : public BaseControlDevice class NesController : public BaseControlDevice
@ -132,4 +133,23 @@ public:
{ {
StrobeProcessWrite(value); StrobeProcessWrite(value);
} }
void DrawController(InputHud& hud)
{
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(30, 7, 3, 3, IsPressed(Buttons::A));
hud.DrawButton(25, 7, 3, 3, IsPressed(Buttons::B));
hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select));
hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start));
hud.DrawNumber(_port + 1, 16, 2);
}
}; };

View file

@ -20,6 +20,7 @@
#include "Shared/Video/VideoDecoder.h" #include "Shared/Video/VideoDecoder.h"
#include "Shared/RewindManager.h" #include "Shared/RewindManager.h"
#include "Shared/NotificationManager.h" #include "Shared/NotificationManager.h"
#include "Shared/RenderedFrame.h"
#include "MemoryOperationType.h" #include "MemoryOperationType.h"
#include "EventType.h" #include "EventType.h"
@ -1071,7 +1072,7 @@ template<class T> void NesPpu<T>::SendFrame()
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer); _emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
} }
RenderedFrame frame(_currentOutputBuffer, NesConstants::ScreenWidth, NesConstants::ScreenHeight, 1.0, _frameCount); RenderedFrame frame(_currentOutputBuffer, NesConstants::ScreenWidth, NesConstants::ScreenHeight, 1.0, _frameCount, _console->GetControlManager()->GetPortStates());
frame.Data = frameData; //HD packs frame.Data = frameData; //HD packs
#ifdef LIBRETRO #ifdef LIBRETRO
@ -1097,7 +1098,7 @@ template<class T> void NesPpu<T>::SendFrameVsDualSystem()
NesConfig& cfg = _settings->GetNesConfig(); NesConfig& cfg = _settings->GetNesConfig();
bool forRewind = _emu->GetRewindManager()->IsRewinding(); bool forRewind = _emu->GetRewindManager()->IsRewinding();
RenderedFrame frame(_currentOutputBuffer, NesConstants::ScreenWidth, NesConstants::ScreenHeight, 1.0, _frameCount); RenderedFrame frame(_currentOutputBuffer, NesConstants::ScreenWidth, NesConstants::ScreenHeight, 1.0, _frameCount, _console->GetControlManager()->GetPortStates());
if(cfg.VsDualVideoOutput == VsDualOutputOption::MainSystemOnly && _console->IsVsMainConsole()) { if(cfg.VsDualVideoOutput == VsDualOutputOption::MainSystemOnly && _console->IsVsMainConsole()) {
_emu->GetVideoDecoder()->UpdateFrame(frame, forRewind, forRewind); _emu->GetVideoDecoder()->UpdateFrame(frame, forRewind, forRewind);
@ -1119,7 +1120,7 @@ template<class T> void NesPpu<T>::SendFrameVsDualSystem()
in2 += NesConstants::ScreenWidth; in2 += NesConstants::ScreenWidth;
} }
RenderedFrame mergedFrame(mergedBuffer, NesConstants::ScreenWidth*2, NesConstants::ScreenHeight, 1.0, _frameCount); RenderedFrame mergedFrame(mergedBuffer, NesConstants::ScreenWidth*2, NesConstants::ScreenHeight, 1.0, _frameCount, _console->GetControlManager()->GetPortStates());
_emu->GetVideoDecoder()->UpdateFrame(mergedFrame, true, forRewind); _emu->GetVideoDecoder()->UpdateFrame(mergedFrame, true, forRewind);
delete[] mergedBuffer; delete[] mergedBuffer;
} }

View file

@ -3,7 +3,9 @@
#include "SNES/Input/SnesController.h" #include "SNES/Input/SnesController.h"
#include "SNES/SnesConsole.h" #include "SNES/SnesConsole.h"
#include "SNES/InternalRegisters.h" #include "SNES/InternalRegisters.h"
#include "Shared/InputHud.h"
#include "Shared/Emulator.h" #include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
string Multitap::GetKeyNames() string Multitap::GetKeyNames()
{ {
@ -149,3 +151,43 @@ void Multitap::WriteRam(uint16_t addr, uint8_t value)
StrobeProcessWrite(value); StrobeProcessWrite(value);
} }
} }
void Multitap::DrawController(InputHud& hud)
{
InputConfig& cfg = _emu->GetSettings()->GetInputConfig();
for(int j = 0; j < 4; j++) {
int port = j == 0 ? _port : (j + 1);
if(cfg.DisplayInputPort[port]) {
DrawController(hud, port);
}
}
}
void Multitap::DrawController(InputHud& hud, int port)
{
int offset = port * Multitap::ButtonCount;
hud.DrawOutline(35, 14);
hud.DrawButton(5, 3, 3, 3, IsPressed(Buttons::Up + offset));
hud.DrawButton(5, 9, 3, 3, IsPressed(Buttons::Down + offset));
hud.DrawButton(2, 6, 3, 3, IsPressed(Buttons::Left + offset));
hud.DrawButton(8, 6, 3, 3, IsPressed(Buttons::Right + offset));
hud.DrawButton(5, 6, 3, 3, false);
hud.DrawButton(27, 3, 3, 3, IsPressed(Buttons::X + offset));
hud.DrawButton(27, 9, 3, 3, IsPressed(Buttons::B + offset));
hud.DrawButton(30, 6, 3, 3, IsPressed(Buttons::A + offset));
hud.DrawButton(24, 6, 3, 3, IsPressed(Buttons::Y + offset));
hud.DrawButton(4, 0, 5, 2, IsPressed(Buttons::L + offset));
hud.DrawButton(26, 0, 5, 2, IsPressed(Buttons::R + offset));
hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select + offset));
hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start + offset));
hud.DrawNumber(port + 1, 16, 2);
hud.EndDrawController();
}

View file

@ -6,6 +6,7 @@
class InternalRegisters; class InternalRegisters;
class SnesController; class SnesController;
class SnesConsole; class SnesConsole;
class InputHud;
class Multitap : public BaseControlDevice class Multitap : public BaseControlDevice
{ {
@ -18,6 +19,8 @@ private:
uint16_t _stateBuffer[4] = {}; uint16_t _stateBuffer[4] = {};
InternalRegisters *_internalRegs = nullptr; InternalRegisters *_internalRegs = nullptr;
void DrawController(InputHud& hud, int port);
protected: protected:
string GetKeyNames() override; string GetKeyNames() override;
void InternalSetStateFromInput() override; void InternalSetStateFromInput() override;
@ -33,4 +36,6 @@ public:
uint8_t ReadRam(uint16_t addr) override; uint8_t ReadRam(uint16_t addr) override;
void WriteRam(uint16_t addr, uint8_t value) override; void WriteRam(uint16_t addr, uint8_t value) override;
void DrawController(InputHud& hud) override;
}; };

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "SNES/Input/SnesController.h" #include "SNES/Input/SnesController.h"
#include "Shared/Emulator.h" #include "Shared/Emulator.h"
#include "Shared/InputHud.h"
SnesController::SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::SnesController, port, keyMappings) SnesController::SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::SnesController, port, keyMappings)
{ {
@ -96,3 +97,27 @@ void SnesController::WriteRam(uint16_t addr, uint8_t value)
{ {
StrobeProcessWrite(value); StrobeProcessWrite(value);
} }
void SnesController::DrawController(InputHud& hud)
{
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(27, 3, 3, 3, IsPressed(Buttons::X));
hud.DrawButton(27, 9, 3, 3, IsPressed(Buttons::B));
hud.DrawButton(30, 6, 3, 3, IsPressed(Buttons::A));
hud.DrawButton(24, 6, 3, 3, IsPressed(Buttons::Y));
hud.DrawButton(4, 0, 5, 2, IsPressed(Buttons::L));
hud.DrawButton(26, 0, 5, 2, IsPressed(Buttons::R));
hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select));
hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start));
hud.DrawNumber(_port + 1, 16, 2);
}

View file

@ -23,4 +23,6 @@ public:
uint8_t ReadRam(uint16_t addr) override; uint8_t ReadRam(uint16_t addr) override;
void WriteRam(uint16_t addr, uint8_t value) override; void WriteRam(uint16_t addr, uint8_t value) override;
void DrawController(InputHud& hud) override;
}; };

View file

@ -3,6 +3,7 @@
#include "Shared/BaseControlDevice.h" #include "Shared/BaseControlDevice.h"
#include "Shared/Interfaces/IKeyManager.h" #include "Shared/Interfaces/IKeyManager.h"
#include "Shared/KeyManager.h" #include "Shared/KeyManager.h"
#include "Shared/InputHud.h"
#include "Shared/Emulator.h" #include "Shared/Emulator.h"
#include "Shared/EmuSettings.h" #include "Shared/EmuSettings.h"
#include "Utilities/Serializer.h" #include "Utilities/Serializer.h"
@ -85,4 +86,14 @@ public:
_stateBuffer = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; _stateBuffer = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
} }
void DrawController(InputHud& hud)
{
hud.DrawOutline(11, 14);
hud.DrawButton(1, 1, 4, 5, IsPressed(Buttons::Left));
hud.DrawButton(6, 1, 4, 5, IsPressed(Buttons::Right));
hud.DrawNumber(_port + 1, 4, 7);
}
}; };

View file

@ -12,6 +12,7 @@
#include "Shared/Video/VideoDecoder.h" #include "Shared/Video/VideoDecoder.h"
#include "Shared/Video/VideoRenderer.h" #include "Shared/Video/VideoRenderer.h"
#include "Shared/NotificationManager.h" #include "Shared/NotificationManager.h"
#include "Shared/RenderedFrame.h"
#include "Shared/MessageManager.h" #include "Shared/MessageManager.h"
#include "EventType.h" #include "EventType.h"
#include "Shared/RewindManager.h" #include "Shared/RewindManager.h"
@ -1476,7 +1477,7 @@ void SnesPpu::SendFrame()
bool isRewinding = _emu->GetRewindManager()->IsRewinding(); bool isRewinding = _emu->GetRewindManager()->IsRewinding();
RenderedFrame frame(_currentBuffer, width, height, _useHighResOutput ? 0.5 : 1.0, _frameCount); RenderedFrame frame(_currentBuffer, width, height, _useHighResOutput ? 0.5 : 1.0, _frameCount, _console->GetControlManager()->GetPortStates());
#ifdef LIBRETRO #ifdef LIBRETRO
_emu->GetVideoDecoder()->UpdateFrame(frame, true, isRewinding); _emu->GetVideoDecoder()->UpdateFrame(frame, true, isRewinding);
#else #else

View file

@ -7,6 +7,7 @@
#include "Utilities/ISerializable.h" #include "Utilities/ISerializable.h"
class Emulator; class Emulator;
class InputHud;
class BaseControlDevice : public ISerializable class BaseControlDevice : public ISerializable
{ {
@ -81,6 +82,8 @@ public:
void SetRawState(ControlDeviceState state); void SetRawState(ControlDeviceState state);
ControlDeviceState GetRawState(); ControlDeviceState GetRawState();
virtual void DrawController(InputHud& hud) {}
virtual uint8_t ReadRam(uint16_t addr) = 0; virtual uint8_t ReadRam(uint16_t addr) = 0;
virtual void WriteRam(uint16_t addr, uint8_t value) = 0; virtual void WriteRam(uint16_t addr, uint8_t value) = 0;

View file

@ -66,7 +66,7 @@ vector<ControllerData> BaseControlManager::GetPortStates()
auto lock = _deviceLock.AcquireSafe(); auto lock = _deviceLock.AcquireSafe();
vector<ControllerData> states; vector<ControllerData> states;
for(int i = 0; i < 2; i++) { for(int i = 0; i < BaseControlDevice::PortCount; i++) {
shared_ptr<BaseControlDevice> device = GetControlDevice(i); shared_ptr<BaseControlDevice> device = GetControlDevice(i);
if(device) { if(device) {
states.push_back({ device->GetControllerType(), device->GetRawState() }); states.push_back({ device->GetControllerType(), device->GetRawState() });

View file

@ -82,7 +82,7 @@ void EmuSettings::SetInputConfig(InputConfig config)
}*/ }*/
} }
InputConfig EmuSettings::GetInputConfig() InputConfig& EmuSettings::GetInputConfig()
{ {
return _input; return _input;
} }

View file

@ -53,7 +53,7 @@ public:
AudioConfig GetAudioConfig(); AudioConfig GetAudioConfig();
void SetInputConfig(InputConfig config); void SetInputConfig(InputConfig config);
InputConfig GetInputConfig(); InputConfig& GetInputConfig();
void SetEmulationConfig(EmulationConfig config); void SetEmulationConfig(EmulationConfig config);
EmulationConfig GetEmulationConfig(); EmulationConfig GetEmulationConfig();

View file

@ -1,180 +1,181 @@
#include "stdafx.h" #include "stdafx.h"
#include "InputHud.h" #include "Shared/InputHud.h"
#include "Shared/Emulator.h"
#include "Shared/BaseControlManager.h"
#include "Shared/Interfaces/IControlManager.h"
#include "Shared/BaseControlDevice.h" #include "Shared/BaseControlDevice.h"
#include "Shared/EmuSettings.h" #include "Shared/EmuSettings.h"
#include "Shared/Video/DebugHud.h" #include "Shared/Video/DebugHud.h"
static constexpr int color[2] = { 0x00111111, 0x00FFFFFF }; static constexpr int color[2] = { 0x00111111, 0x00FFFFFF };
InputHud::InputHud(Emulator* emu) InputHud::InputHud(Emulator* emu, DebugHud* hud)
{ {
_emu = emu; _emu = emu;
_hud = hud;
} }
void InputHud::DrawController(int port, ControlDeviceState state, int x, int y, int frameNumber) void InputHud::DrawButton(int x, int y, int width, int height, bool pressed)
{ {
//TODO _hud->DrawRectangle(_xOffset + x, _yOffset + y, width, height, color[pressed], true, 1);
/*SnesController controller(_console, 0, KeyMappingSet()); }
controller.SetRawState(state);
shared_ptr<DebugHud> hud = _console->GetDebugHud();
hud->DrawRectangle(0 + x, 0 + y, 35, 14, 0x80CCCCCC, true, 1, frameNumber);
hud->DrawRectangle(0 + x, 0 + y, 35, 14, color[0], false, 1, frameNumber);
hud->DrawRectangle(5 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Up)], true, 1, frameNumber);
hud->DrawRectangle(5 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Down)], true, 1, frameNumber);
hud->DrawRectangle(2 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Left)], true, 1, frameNumber);
hud->DrawRectangle(8 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Right)], true, 1, frameNumber);
hud->DrawRectangle(5 + x, 6 + y, 3, 3, color[0], true, 1, frameNumber);
hud->DrawRectangle(27 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::X)], true, 1, frameNumber);
hud->DrawRectangle(27 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::B)], true, 1, frameNumber);
hud->DrawRectangle(30 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::A)], true, 1, frameNumber);
hud->DrawRectangle(24 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Y)], true, 1, frameNumber);
hud->DrawRectangle(4 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::L)], true, 1, frameNumber);
hud->DrawRectangle(26 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::R)], true, 1, frameNumber);
hud->DrawRectangle(13 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Select)], true, 1, frameNumber);
hud->DrawRectangle(18 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Start)], true, 1, frameNumber);
switch(port) {
case 0:
//1
hud->DrawLine(17 + x, 2 + y, 17 + x, 6 + y, color[0], 1, frameNumber);
hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber);
hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber);
break;
void InputHud::DrawNumber(int number, int x, int y)
{
switch(number) {
case 1: case 1:
//2 _hud->DrawLine(x+1 + _xOffset, y + _yOffset, x+1 + _xOffset, 4 + y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); _hud->DrawLine(x + _xOffset, 4 + y + _yOffset, x+2 + _xOffset, 4 + y + _yOffset, color[0], 1);
hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); _hud->DrawPixel(x + _xOffset, 1 + y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber);
hud->DrawPixel(16 + x, 5 + y, color[0], 1, frameNumber);
hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber);
break; break;
case 2: case 2:
//3 _hud->DrawLine(x + _xOffset, y + _yOffset, x+2 + _xOffset, y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); _hud->DrawPixel(x+2 + _xOffset, 1 + y + _yOffset, color[0], 1);
hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); _hud->DrawLine(x + _xOffset, 2 + y + _yOffset, x+2 + _xOffset, 2 + y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); _hud->DrawPixel(x + _xOffset, 3 + y + _yOffset, color[0], 1);
hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); _hud->DrawLine(x + _xOffset, 4 + y + _yOffset, x+2 + _xOffset, 4 + y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber);
break; break;
case 3: case 3:
//4 _hud->DrawLine(x + _xOffset, y + _yOffset, x+2 + _xOffset, y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 2 + y, 16 + x, 4 + y, color[0], 1, frameNumber); _hud->DrawPixel(x+2 + _xOffset, 1 + y + _yOffset, color[0], 1);
hud->DrawLine(18 + x, 2 + y, 18 + x, 6 + y, color[0], 1, frameNumber); _hud->DrawLine(x + _xOffset, 2 + y + _yOffset, x+2 + _xOffset, 2 + y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); _hud->DrawPixel(x+2 + _xOffset, 3 + y + _yOffset, color[0], 1);
_hud->DrawLine(x + _xOffset, 4 + y + _yOffset, x+2 + _xOffset, 4 + y + _yOffset, color[0], 1);
break; break;
case 4: case 4:
//5 _hud->DrawLine(x + _xOffset, y + _yOffset, x + _xOffset, 2 + y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); _hud->DrawLine(x+2 + _xOffset, y + _yOffset, x+2 + _xOffset, 4 + y + _yOffset, color[0], 1);
hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); _hud->DrawLine(x + _xOffset, 2 + y + _yOffset, x+2 + _xOffset, 2 + y + _yOffset, color[0], 1);
hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber);
hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber);
hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber);
break; break;
}*/
case 5:
_hud->DrawLine(x + _xOffset, y + _yOffset, x+2 + _xOffset, y + _yOffset, color[0], 1);
_hud->DrawPixel(x + _xOffset, 1 + y + _yOffset, color[0], 1);
_hud->DrawLine(x + _xOffset, 2 + y + _yOffset, x+2 + _xOffset, 2 + y + _yOffset, color[0], 1);
_hud->DrawPixel(x+2 + _xOffset, 3 + y + _yOffset, color[0], 1);
_hud->DrawLine(x + _xOffset, 4 + y + _yOffset, x+2 + _xOffset, 4 + y + _yOffset, color[0], 1);
break;
default:
break;
}
} }
void InputHud::DrawControllers(OverscanDimensions overscan, int frameNumber) void InputHud::DrawOutline(int width, int height)
{ {
//TODO InputConfig& cfg = _emu->GetSettings()->GetInputConfig();
/*
vector<ControllerData> controllerData = _console->GetControlManager()->GetPortStates();
InputConfig cfg = _console->GetSettings()->GetInputConfig();
int xStart;
int yStart;
int xOffset = cfg.DisplayInputHorizontally ? 38 : 0;
int yOffset = cfg.DisplayInputHorizontally ? 0 : 16;
switch(cfg.DisplayInputPosition) { switch(cfg.DisplayInputPosition) {
default: default:
case InputDisplayPosition::TopLeft: case InputDisplayPosition::TopLeft:
xStart = overscan.Left + 3;
yStart = overscan.Top + 3;
break; break;
case InputDisplayPosition::TopRight: case InputDisplayPosition::TopRight:
xStart = 256 - overscan.Right - 38; _xOffset -= width + 1;
yStart = overscan.Top + 3;
xOffset = -xOffset;
break; break;
case InputDisplayPosition::BottomLeft: case InputDisplayPosition::BottomLeft:
xStart = overscan.Left + 3; _yOffset -= height + 1;
yStart = 240 - overscan.Bottom - 18;
yOffset = -yOffset;
break; break;
case InputDisplayPosition::BottomRight: case InputDisplayPosition::BottomRight:
xStart = 256 - overscan.Right - 38; _yOffset -= height + 1;
yStart = 240 - overscan.Bottom - 18; _xOffset -= width + 1;
xOffset = -xOffset;
yOffset = -yOffset;
break; break;
} }
for(int i = 0; i < (int)controllerData.size(); i++) { _hud->DrawRectangle(_xOffset, _yOffset, width, height, 0x80CCCCCC, true, 1);
if(controllerData[i].Type == ControllerType::SnesController) { _hud->DrawRectangle(_xOffset, _yOffset, width, height, color[0], false, 1);
if(cfg.DisplayInputPort[i]) {
DrawController(i, controllerData[i].State, xStart, yStart, frameNumber); _outlineWidth = width;
xStart += xOffset; _outlineHeight = height;
yStart += yOffset; }
}
} else if(controllerData[i].Type == ControllerType::Multitap) { void InputHud::DrawController(ControllerType controllerType, int port, ControlDeviceState state)
uint64_t rawData = 0; {
for(int j = (int)controllerData[i].State.State.size() - 1; j >= 0; j--) { shared_ptr<BaseControlDevice> controller = ((BaseControlManager*)_emu->GetControlManager())->CreateControllerDevice(controllerType, port);
rawData <<= 8; if(!controller) {
rawData |= controllerData[i].State.State[j]; return;
} }
ControlDeviceState controllers[4] = {}; controller->SetRawState(state);
for(int j = 0; j < 4; j++) { controller->DrawController(*this);
controllers[j].State.push_back(rawData & 0xFF); EndDrawController();
controllers[j].State.push_back((rawData >> 8) & 0x0F); }
rawData >>= 12;
} void InputHud::EndDrawController()
{
if(cfg.DisplayInputPort[i]) { if(_outlineHeight > 0 && _outlineWidth > 0) {
DrawController(i, controllers[0], xStart, yStart, frameNumber); InputConfig& cfg = _emu->GetSettings()->GetInputConfig();
xStart += xOffset;
yStart += yOffset; switch(cfg.DisplayInputPosition) {
} default:
case InputDisplayPosition::TopLeft:
for(int j = 1; j < 4; j++) { if(cfg.DisplayInputHorizontally) {
if(cfg.DisplayInputPort[j + 1]) { _xOffset += _outlineWidth + 1;
DrawController(j + 1, controllers[j], xStart, yStart, frameNumber); } else {
xStart += xOffset; _yOffset += _outlineHeight + 1;
yStart += yOffset; }
} break;
}
} else if(controllerData[i].Type == ControllerType::SuperScope) { case InputDisplayPosition::TopRight:
if(cfg.DisplayInputPort[i]) { if(!cfg.DisplayInputHorizontally) {
SuperScope scope(_console, 0, KeyMappingSet()); _xOffset += _outlineWidth + 1;
scope.SetRawState(controllerData[i].State); _yOffset += _outlineHeight + 1;
MousePosition pos = scope.GetCoordinates(); }
break;
shared_ptr<DebugHud> hud = _console->GetDebugHud();
hud->DrawRectangle(pos.X - 1, pos.Y - 1, 3, 3, 0x00111111, true, 1, frameNumber); case InputDisplayPosition::BottomLeft:
hud->DrawRectangle(pos.X - 1, pos.Y - 1, 3, 3, 0x80CCCCCC, false, 1, frameNumber); if(cfg.DisplayInputHorizontally) {
} _xOffset += _outlineWidth + 1;
} else if(controllerData[i].Type == ControllerType::SnesMouse) { _yOffset += _outlineHeight + 1;
if(cfg.DisplayInputPort[i]) { }
SnesMouse mouse(_console, 0); break;
mouse.SetRawState(controllerData[i].State);
case InputDisplayPosition::BottomRight:
shared_ptr<DebugHud> hud = _console->GetDebugHud(); if(cfg.DisplayInputHorizontally) {
hud->DrawRectangle(xStart + 12, yStart, 11, 14, 0x00AAAAAA, true, 1, frameNumber); _yOffset += _outlineHeight + 1;
hud->DrawRectangle(xStart + 12, yStart, 11, 14, color[0], false, 1, frameNumber); } else {
hud->DrawRectangle(xStart + 13, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Left)], true, 1, frameNumber); _xOffset += _outlineWidth + 1;
hud->DrawRectangle(xStart + 18, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Right)], true, 1, frameNumber); }
break;
xStart += xOffset; }
yStart += yOffset;
} _outlineWidth = 0;
} _outlineHeight = 0;
}*/ }
}
void InputHud::DrawControllers(FrameInfo size, vector<ControllerData> controllerData)
{
InputConfig& cfg = _emu->GetSettings()->GetInputConfig();
switch(cfg.DisplayInputPosition) {
default:
case InputDisplayPosition::TopLeft:
_xOffset = 2;
_yOffset = 2;
break;
case InputDisplayPosition::TopRight:
_xOffset = size.Width - 1;
_yOffset = 2;
break;
case InputDisplayPosition::BottomLeft:
_xOffset = 2;
_yOffset = size.Height - 1;
break;
case InputDisplayPosition::BottomRight:
_xOffset = size.Width - 1;
_yOffset = size.Height - 1;
break;
}
for(int i = 0; i < (int)controllerData.size(); i++) {
if(controllerData[i].Type != ControllerType::None) {
DrawController(controllerData[i].Type, i, controllerData[i].State);
}
}
} }

View file

@ -4,16 +4,28 @@
#include "ControlDeviceState.h" #include "ControlDeviceState.h"
class Emulator; class Emulator;
class DebugHud;
class InputHud class InputHud
{ {
private: private:
Emulator* _emu; Emulator* _emu;
DebugHud* _hud;
void DrawController(int port, ControlDeviceState state, int x, int y, int frameNumber); int _xOffset = 0;
int _yOffset = 0;
int _outlineWidth = 0;
int _outlineHeight = 0;
void DrawController(ControllerType type, int port, ControlDeviceState state);
public: public:
InputHud(Emulator *emu); InputHud(Emulator *emu, DebugHud* hud);
void DrawControllers(OverscanDimensions overscan, int frameNumber); void DrawOutline(int width, int height);
void DrawButton(int x, int y, int width, int height, bool pressed);
void DrawNumber(int number, int x, int y);
void EndDrawController();
void DrawControllers(FrameInfo size, vector<ControllerData> controllerData);
}; };

View file

@ -4,6 +4,7 @@
#include "IInputProvider.h" #include "IInputProvider.h"
enum class ControllerType; enum class ControllerType;
struct ControllerData;
class IControlManager class IControlManager
{ {
@ -20,6 +21,8 @@ public:
virtual shared_ptr<BaseControlDevice> CreateControllerDevice(ControllerType type, uint8_t port) = 0; virtual shared_ptr<BaseControlDevice> CreateControllerDevice(ControllerType type, uint8_t port) = 0;
virtual bool HasControlDevice(ControllerType type) = 0; virtual bool HasControlDevice(ControllerType type) = 0;
virtual vector<ControllerData> GetPortStates() = 0;
virtual void SetPollCounter(uint32_t pollCounter) = 0; virtual void SetPollCounter(uint32_t pollCounter) = 0;
virtual uint32_t GetPollCounter() = 0; virtual uint32_t GetPollCounter() = 0;

View file

@ -3,11 +3,13 @@
#include "stdafx.h" #include "stdafx.h"
#include "Shared/SettingTypes.h" #include "Shared/SettingTypes.h"
struct RenderedFrame;
class IRenderingDevice class IRenderingDevice
{ {
public: public:
virtual ~IRenderingDevice() {} virtual ~IRenderingDevice() {}
virtual void UpdateFrame(RenderedFrame frame) = 0; virtual void UpdateFrame(RenderedFrame& frame) = 0;
virtual void Render(uint32_t* hudBuffer, uint32_t width, uint32_t height) = 0; virtual void Render(uint32_t* hudBuffer, uint32_t width, uint32_t height) = 0;
virtual void Reset() = 0; virtual void Reset() = 0;
virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = 0; virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = 0;

View file

@ -0,0 +1,38 @@
#pragma once
#include "stdafx.h"
#include "Shared/SettingTypes.h"
#include "Shared/ControlDeviceState.h"
struct RenderedFrame
{
void* FrameBuffer = nullptr;
void* Data = nullptr; //Used by HD packs
uint32_t Width = 256;
uint32_t Height = 240;
double Scale = 1.0;
uint32_t FrameNumber = 0;
vector<ControllerData> InputData;
RenderedFrame()
{}
RenderedFrame(void* buffer, uint32_t width, uint32_t height, double scale = 1.0, uint32_t frameNumber = 0) :
FrameBuffer(buffer),
Width(width),
Height(height),
Scale(scale),
FrameNumber(frameNumber),
Data(nullptr),
InputData({})
{}
RenderedFrame(void* buffer, uint32_t width, uint32_t height, double scale, uint32_t frameNumber, vector<ControllerData> inputData) :
FrameBuffer(buffer),
Width(width),
Height(height),
Scale(scale),
FrameNumber(frameNumber),
Data(nullptr),
InputData(inputData)
{}
};

View file

@ -6,6 +6,7 @@
#include "Shared/Video/VideoRenderer.h" #include "Shared/Video/VideoRenderer.h"
#include "Shared/Audio/SoundMixer.h" #include "Shared/Audio/SoundMixer.h"
#include "Shared/BaseControlDevice.h" #include "Shared/BaseControlDevice.h"
#include "Shared/RenderedFrame.h"
#include "Shared/Interfaces/IControlManager.h" #include "Shared/Interfaces/IControlManager.h"
RewindManager::RewindManager(Emulator* emu) RewindManager::RewindManager(Emulator* emu)
@ -220,7 +221,7 @@ void RewindManager::ProcessEndOfFrame()
} }
} }
void RewindManager::ProcessFrame(RenderedFrame frame, bool forRewind) void RewindManager::ProcessFrame(RenderedFrame& frame, bool forRewind)
{ {
if(_rewindState == RewindState::Starting || _rewindState == RewindState::Started) { if(_rewindState == RewindState::Starting || _rewindState == RewindState::Started) {
if(!forRewind) { if(!forRewind) {
@ -354,7 +355,7 @@ bool RewindManager::HasHistory()
return _hasHistory; return _hasHistory;
} }
void RewindManager::SendFrame(RenderedFrame frame, bool forRewind) void RewindManager::SendFrame(RenderedFrame& frame, bool forRewind)
{ {
ProcessFrame(frame, forRewind); ProcessFrame(frame, forRewind);
} }

View file

@ -8,6 +8,7 @@
class Emulator; class Emulator;
class EmuSettings; class EmuSettings;
struct RenderedFrame;
enum class RewindState enum class RewindState
{ {
@ -55,7 +56,7 @@ private:
void Stop(); void Stop();
void ForceStop(); void ForceStop();
void ProcessFrame(RenderedFrame frame, bool forRewind); void ProcessFrame(RenderedFrame& frame, bool forRewind);
bool ProcessAudio(int16_t* soundBuffer, uint32_t sampleCount); bool ProcessAudio(int16_t* soundBuffer, uint32_t sampleCount);
void ClearBuffer(); void ClearBuffer();
@ -78,6 +79,6 @@ public:
bool HasHistory(); bool HasHistory();
void SendFrame(RenderedFrame frame, bool forRewind); void SendFrame(RenderedFrame& frame, bool forRewind);
bool SendAudio(int16_t *soundBuffer, uint32_t sampleCount); bool SendAudio(int16_t *soundBuffer, uint32_t sampleCount);
}; };

View file

@ -8,6 +8,7 @@
#include "Shared/Emulator.h" #include "Shared/Emulator.h"
#include "Shared/EmuSettings.h" #include "Shared/EmuSettings.h"
#include "Shared/Movies/MovieManager.h" #include "Shared/Movies/MovieManager.h"
#include "Shared/RenderedFrame.h"
#include "EventType.h" #include "EventType.h"
#include "Debugger/Debugger.h" #include "Debugger/Debugger.h"
#include "Netplay/GameClient.h" #include "Netplay/GameClient.h"

View file

@ -505,30 +505,6 @@ struct OverscanDimensions
uint32_t Bottom = 0; uint32_t Bottom = 0;
}; };
struct RenderedFrame
{
void* FrameBuffer = nullptr;
void* Data = nullptr; //Used by HD packs
uint32_t Width = 256;
uint32_t Height = 240;
double Scale = 1.0;
uint32_t FrameNumber = 0;
RenderedFrame()
{
}
RenderedFrame(void* buffer, uint32_t width, uint32_t height, double scale = 1.0, uint32_t frameNumber = 0) :
FrameBuffer(buffer),
Width(width),
Height(height),
Scale(scale),
FrameNumber(frameNumber),
Data(nullptr)
{
}
};
struct FrameInfo struct FrameInfo
{ {
uint32_t Width; uint32_t Width;

View file

@ -17,6 +17,22 @@ protected:
int _yScale = 1; int _yScale = 1;
virtual void InternalDraw() = 0; virtual void InternalDraw() = 0;
void InternalDrawPixel(int32_t offset, int color, uint32_t alpha)
{
if(alpha != 0xFF000000) {
if(_argbBuffer[offset] == 0) {
//When drawing on an empty background, premultiply channels & preserve alpha value
//This is needed for hardware blending between the HUD and the game screen
BlendColors((uint8_t*)&_argbBuffer[offset], (uint8_t*)&color, true);
} else {
BlendColors((uint8_t*)&_argbBuffer[offset], (uint8_t*)&color);
}
} else {
_argbBuffer[offset] = color;
}
}
void DrawPixel(uint32_t x, uint32_t y, int color) void DrawPixel(uint32_t x, uint32_t y, int color)
{ {
uint32_t alpha = (color & 0xFF000000); uint32_t alpha = (color & 0xFF000000);
@ -30,11 +46,7 @@ protected:
return; return;
} }
if(alpha != 0xFF000000) { InternalDrawPixel(offset, color, alpha);
BlendColors((uint8_t*)&_argbBuffer[offset], (uint8_t*)&color);
} else {
_argbBuffer[offset] = color;
}
} else { } else {
int xPixelCount = _useIntegerScaling ? (int)std::floor(_xScale): (int)((x + 1)*_xScale) - (int)(x*_xScale); int xPixelCount = _useIntegerScaling ? (int)std::floor(_xScale): (int)((x + 1)*_xScale) - (int)(x*_xScale);
x = (int)(x * (_useIntegerScaling ? (int)std::floor(_xScale) : _xScale)); x = (int)(x * (_useIntegerScaling ? (int)std::floor(_xScale) : _xScale));
@ -48,25 +60,25 @@ protected:
continue; continue;
} }
if(alpha != 0xFF000000) { InternalDrawPixel(offset, color, alpha);
BlendColors((uint8_t*)&_argbBuffer[offset], (uint8_t*)&color);
} else {
_argbBuffer[offset] = color;
}
} }
} }
} }
} }
} }
__forceinline void BlendColors(uint8_t output[4], uint8_t input[4]) __forceinline void BlendColors(uint8_t output[4], uint8_t input[4], bool keepAlpha = false)
{ {
uint8_t alpha = input[3] + 1; uint8_t alpha = input[3] + 1;
uint8_t invertedAlpha = 256 - input[3]; uint8_t invertedAlpha = 256 - input[3];
output[0] = (uint8_t)((alpha * input[0] + invertedAlpha * output[0]) >> 8); output[0] = (uint8_t)((alpha * input[0] + invertedAlpha * output[0]) >> 8);
output[1] = (uint8_t)((alpha * input[1] + invertedAlpha * output[1]) >> 8); output[1] = (uint8_t)((alpha * input[1] + invertedAlpha * output[1]) >> 8);
output[2] = (uint8_t)((alpha * input[2] + invertedAlpha * output[2]) >> 8); output[2] = (uint8_t)((alpha * input[2] + invertedAlpha * output[2]) >> 8);
output[3] = 0xFF; if(keepAlpha) {
output[3] = input[3];
} else {
output[3] = 0xFF;
}
} }
public: public:

View file

@ -11,6 +11,7 @@
#include "Shared/Video/ScaleFilter.h" #include "Shared/Video/ScaleFilter.h"
#include "Shared/Video/DebugHud.h" #include "Shared/Video/DebugHud.h"
#include "Shared/InputHud.h" #include "Shared/InputHud.h"
#include "Shared/RenderedFrame.h"
#include "Shared/Video/SystemHud.h" #include "Shared/Video/SystemHud.h"
#include "SNES/CartTypes.h" #include "SNES/CartTypes.h"
@ -97,7 +98,7 @@ void VideoDecoder::DecodeFrame(bool forRewind)
overscan.Bottom *= _scaleFilter->GetScale(); overscan.Bottom *= _scaleFilter->GetScale();
} }
RenderedFrame convertedFrame((void*)outputBuffer, frameSize.Width, frameSize.Height, _frame.Scale, _frame.FrameNumber); RenderedFrame convertedFrame((void*)outputBuffer, frameSize.Width, frameSize.Height, _frame.Scale, _frame.FrameNumber, _frame.InputData);
_emu->GetDebugHud()->Draw(outputBuffer, frameSize, overscan, _frame.FrameNumber, true); _emu->GetDebugHud()->Draw(outputBuffer, frameSize, overscan, _frame.FrameNumber, true);

View file

@ -3,6 +3,7 @@
#include "Utilities/SimpleLock.h" #include "Utilities/SimpleLock.h"
#include "Utilities/AutoResetEvent.h" #include "Utilities/AutoResetEvent.h"
#include "Shared/SettingTypes.h" #include "Shared/SettingTypes.h"
#include "Shared/RenderedFrame.h"
class BaseVideoFilter; class BaseVideoFilter;
class ScaleFilter; class ScaleFilter;

View file

@ -19,6 +19,7 @@ VideoRenderer::VideoRenderer(Emulator* emu)
_rendererHud.reset(new DebugHud()); _rendererHud.reset(new DebugHud());
_systemHud.reset(new SystemHud(_emu, _rendererHud.get())); _systemHud.reset(new SystemHud(_emu, _rendererHud.get()));
_inputHud.reset(new InputHud(emu, _rendererHud.get()));
_hudSurface = new uint32_t[256*240]; _hudSurface = new uint32_t[256*240];
_hudSize.Width = 256; _hudSize.Width = 256;
@ -89,7 +90,14 @@ void VideoRenderer::RenderThread()
_hudSize = size; _hudSize = size;
} }
RenderedFrame frame;
{
_frameLock.AcquireSafe();
frame = _lastFrame;
}
memset(_hudSurface, 0, _hudSize.Width * _hudSize.Height * sizeof(uint32_t)); memset(_hudSurface, 0, _hudSize.Width * _hudSize.Height * sizeof(uint32_t));
_inputHud->DrawControllers(_hudSize, frame.InputData);
_systemHud->Draw(_hudSize.Width, _hudSize.Height); _systemHud->Draw(_hudSize.Width, _hudSize.Height);
_rendererHud->Draw(_hudSurface, _hudSize, {}, 0, false); _rendererHud->Draw(_hudSurface, _hudSize, {}, 0, false);
_renderer->Render(_hudSurface, _hudSize.Width, _hudSize.Height); _renderer->Render(_hudSurface, _hudSize.Width, _hudSize.Height);
@ -97,13 +105,18 @@ void VideoRenderer::RenderThread()
} }
} }
void VideoRenderer::UpdateFrame(RenderedFrame frame) void VideoRenderer::UpdateFrame(RenderedFrame& frame)
{ {
shared_ptr<IVideoRecorder> recorder = _recorder; shared_ptr<IVideoRecorder> recorder = _recorder;
if(recorder) { if(recorder) {
recorder->AddFrame(frame.FrameBuffer, frame.Width, frame.Height, _emu->GetFps()); recorder->AddFrame(frame.FrameBuffer, frame.Width, frame.Height, _emu->GetFps());
} }
{
_frameLock.AcquireSafe();
_lastFrame = frame;
}
if(_renderer) { if(_renderer) {
_renderer->UpdateFrame(frame); _renderer->UpdateFrame(frame);
_waitForRender.Signal(); _waitForRender.Signal();

View file

@ -2,6 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include <thread> #include <thread>
#include "Shared/SettingTypes.h" #include "Shared/SettingTypes.h"
#include "Shared/RenderedFrame.h"
#include "Utilities/AutoResetEvent.h" #include "Utilities/AutoResetEvent.h"
#include "Utilities/SimpleLock.h" #include "Utilities/SimpleLock.h"
@ -9,6 +10,7 @@ class IRenderingDevice;
class Emulator; class Emulator;
class SystemHud; class SystemHud;
class DebugHud; class DebugHud;
class InputHud;
class IVideoRecorder; class IVideoRecorder;
enum class VideoCodec; enum class VideoCodec;
@ -29,9 +31,13 @@ private:
unique_ptr<DebugHud> _rendererHud; unique_ptr<DebugHud> _rendererHud;
unique_ptr<SystemHud> _systemHud; unique_ptr<SystemHud> _systemHud;
unique_ptr<InputHud> _inputHud;
uint32_t* _hudSurface = nullptr; uint32_t* _hudSurface = nullptr;
FrameInfo _hudSize = {}; FrameInfo _hudSize = {};
RenderedFrame _lastFrame;
SimpleLock _frameLock;
shared_ptr<IVideoRecorder> _recorder; shared_ptr<IVideoRecorder> _recorder;
void RenderThread(); void RenderThread();
@ -46,7 +52,7 @@ public:
void StartThread(); void StartThread();
void StopThread(); void StopThread();
void UpdateFrame(RenderedFrame frame); void UpdateFrame(RenderedFrame& frame);
void RegisterRenderingDevice(IRenderingDevice *renderer); void RegisterRenderingDevice(IRenderingDevice *renderer);
void UnregisterRenderingDevice(IRenderingDevice *renderer); void UnregisterRenderingDevice(IRenderingDevice *renderer);

View file

@ -527,6 +527,8 @@ namespace Mesen.Debugger.Utilities
Audio, Audio,
[IconFile("DipSwitches")] [IconFile("DipSwitches")]
Emulation, Emulation,
[IconFile("Controller")]
Input,
[IconFile("VideoOptions")] [IconFile("VideoOptions")]
Video, Video,
[IconFile("NesIcon")] [IconFile("NesIcon")]

View file

@ -98,24 +98,29 @@
<Control ID="btnSetupMultitap2">Setup</Control> <Control ID="btnSetupMultitap2">Setup</Control>
<Control ID="btnSetupMultitap3">Setup</Control> <Control ID="btnSetupMultitap3">Setup</Control>
<Control ID="btnSetupMultitap4">Setup</Control> <Control ID="btnSetupMultitap4">Setup</Control>
<Control ID="lblKeyBinding">Warning: Your current configuration contains conflicting key bindings - some physical buttons on your keyboard or gamepad are mapped to multiple buttons on the NES controller. If this is not intentional, please review and correct your key bindings.</Control>
</Form>
<Form ID="InputConfigView">
<Control ID="tpgGeneral">General</Control>
<Control ID="lblSmall">Small</Control>
<Control ID="lblLarge">Large</Control>
<Control ID="lblDeadzone">Controller axis deadzone size:</Control>
<Control ID="tpgAdvanced">Advanced</Control> <Control ID="lblSensitivity">Mouse speed:</Control>
<Control ID="grpDisplayInput">Display Controller Input</Control> <Control ID="lblLow">Slow</Control>
<Control ID="lblHigh">Fast</Control>
<Control ID="tpgDisplay">Display</Control>
<Control ID="lblDisplayInputPorts">Display ports: </Control>
<Control ID="chkDisplayPort1">Port 1</Control> <Control ID="chkDisplayPort1">Port 1</Control>
<Control ID="chkDisplayPort2">Port 2</Control> <Control ID="chkDisplayPort2">Port 2</Control>
<Control ID="chkDisplayPort3">Port 3</Control> <Control ID="chkDisplayPort3">Port 3</Control>
<Control ID="chkDisplayPort4">Port 4</Control> <Control ID="chkDisplayPort4">Port 4</Control>
<Control ID="chkDisplayPort5">Port 5</Control> <Control ID="chkDisplayPort5">Port 5</Control>
<Control ID="lblDisplayPosition">Display Position:</Control> <Control ID="lblDisplayPosition">Display position:</Control>
<Control ID="chkDisplayInputHorizontally">Display horizontally</Control> <Control ID="chkDisplayInputHorizontally">Horizontal display</Control>
<Control ID="lblSmall">Small</Control>
<Control ID="lblLarge">Large</Control>
<Control ID="lblDeadzone">Controller axis deadzone size:</Control>
<Control ID="chkHideMousePointerForZapper">Hide mouse pointer when using zapper</Control> <Control ID="chkHideMousePointerForZapper">Hide mouse pointer when using zapper</Control>
<Control ID="lblKeyBinding">Warning: Your current configuration contains conflicting key bindings - some physical buttons on your keyboard or gamepad are mapped to multiple buttons on the NES controller. If this is not intentional, please review and correct your key bindings.</Control>
</Form> </Form>
<Form ID="OverscanConfig"> <Form ID="OverscanConfig">
<Control ID="lblLeft">Left</Control> <Control ID="lblLeft">Left</Control>
@ -359,6 +364,7 @@
<Control ID="tabAudio">Audio</Control> <Control ID="tabAudio">Audio</Control>
<Control ID="tabEmulation">Emulation</Control> <Control ID="tabEmulation">Emulation</Control>
<Control ID="tabInput">Input</Control>
<Control ID="tabVideo">Video</Control> <Control ID="tabVideo">Video</Control>
<Control ID="tabNes">NES</Control> <Control ID="tabNes">NES</Control>
<Control ID="tabSnes">SNES</Control> <Control ID="tabSnes">SNES</Control>
@ -2160,6 +2166,7 @@ x == [$150] || y == [10]
<Value ID="Audio">Audio</Value> <Value ID="Audio">Audio</Value>
<Value ID="Emulation">Emulation</Value> <Value ID="Emulation">Emulation</Value>
<Value ID="Input">Input</Value>
<Value ID="Video">Video</Value> <Value ID="Video">Video</Value>
<Value ID="Nes">NES</Value> <Value ID="Nes">NES</Value>
<Value ID="Snes">SNES</Value> <Value ID="Snes">SNES</Value>

View file

@ -323,6 +323,9 @@
<Compile Update="Debugger\Windows\MemoryToolsWindow.axaml.cs"> <Compile Update="Debugger\Windows\MemoryToolsWindow.axaml.cs">
<DependentUpon>MemoryToolsWindow.axaml</DependentUpon> <DependentUpon>MemoryToolsWindow.axaml</DependentUpon>
</Compile> </Compile>
<Compile Update="Views\InputConfigView.axaml.cs">
<DependentUpon>InputConfigView.axaml</DependentUpon>
</Compile>
<Compile Update="Views\MainMenuView.axaml.cs"> <Compile Update="Views\MainMenuView.axaml.cs">
<DependentUpon>MainMenuView.axaml</DependentUpon> <DependentUpon>MainMenuView.axaml</DependentUpon>
</Compile> </Compile>

View file

@ -1,6 +1,7 @@
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System; using System;
using System.Collections;
using System.ComponentModel; using System.ComponentModel;
using System.Reflection; using System.Reflection;
@ -12,8 +13,15 @@ namespace Mesen.Utilities
{ {
foreach(PropertyInfo prop in target.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { foreach(PropertyInfo prop in target.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
if(prop.GetCustomAttribute<ReactiveAttribute>() != null) { if(prop.GetCustomAttribute<ReactiveAttribute>() != null) {
if(prop.GetValue(target) is ReactiveObject propValue) { object? value = prop.GetValue(target);
if(value is ReactiveObject propValue) {
ReactiveHelper.RegisterRecursiveObserver(propValue, handler); ReactiveHelper.RegisterRecursiveObserver(propValue, handler);
} else if(value is IList list) {
foreach(object listValue in list) {
if(listValue is ReactiveObject) {
ReactiveHelper.RegisterRecursiveObserver((ReactiveObject)listValue, handler);
}
}
} }
} }
} }
@ -27,8 +35,15 @@ namespace Mesen.Utilities
{ {
foreach(PropertyInfo prop in target.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { foreach(PropertyInfo prop in target.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
if(prop.GetCustomAttribute<ReactiveAttribute>() != null) { if(prop.GetCustomAttribute<ReactiveAttribute>() != null) {
if(prop.GetValue(target) is ReactiveObject propValue) { object? value = prop.GetValue(target);
if(value is ReactiveObject propValue) {
ReactiveHelper.UnregisterRecursiveObserver(propValue, handler); ReactiveHelper.UnregisterRecursiveObserver(propValue, handler);
} else if(value is IList list) {
foreach(object listValue in list) {
if(listValue is ReactiveObject) {
ReactiveHelper.UnregisterRecursiveObserver((ReactiveObject)listValue, handler);
}
}
} }
} }
} }

View file

@ -10,6 +10,7 @@ namespace Mesen.ViewModels
public class ConfigViewModel : DisposableViewModel public class ConfigViewModel : DisposableViewModel
{ {
[Reactive] public AudioConfigViewModel? Audio { get; set; } [Reactive] public AudioConfigViewModel? Audio { get; set; }
[Reactive] public InputConfigViewModel? Input { get; set; }
[Reactive] public VideoConfigViewModel? Video { get; set; } [Reactive] public VideoConfigViewModel? Video { get; set; }
[Reactive] public PreferencesConfigViewModel? Preferences { get; set; } [Reactive] public PreferencesConfigViewModel? Preferences { get; set; }
[Reactive] public EmulationConfigViewModel? Emulation { get; set; } [Reactive] public EmulationConfigViewModel? Emulation { get; set; }
@ -38,6 +39,7 @@ namespace Mesen.ViewModels
switch(tab) { switch(tab) {
case ConfigWindowTab.Audio: Audio ??= AddDisposable(new AudioConfigViewModel()); break; case ConfigWindowTab.Audio: Audio ??= AddDisposable(new AudioConfigViewModel()); break;
case ConfigWindowTab.Emulation: Emulation ??= AddDisposable(new EmulationConfigViewModel()); break; case ConfigWindowTab.Emulation: Emulation ??= AddDisposable(new EmulationConfigViewModel()); break;
case ConfigWindowTab.Input: Input ??= AddDisposable(new InputConfigViewModel()); break;
case ConfigWindowTab.Video: Video ??= AddDisposable(new VideoConfigViewModel()); break; case ConfigWindowTab.Video: Video ??= AddDisposable(new VideoConfigViewModel()); break;
case ConfigWindowTab.Nes: case ConfigWindowTab.Nes:
@ -63,6 +65,7 @@ namespace Mesen.ViewModels
} }
ConfigManager.Config.Audio = Audio?.Config.Clone() ?? ConfigManager.Config.Audio; ConfigManager.Config.Audio = Audio?.Config.Clone() ?? ConfigManager.Config.Audio;
ConfigManager.Config.Input = Input?.Config.Clone() ?? ConfigManager.Config.Input;
ConfigManager.Config.Video = Video?.Config.Clone() ?? ConfigManager.Config.Video; ConfigManager.Config.Video = Video?.Config.Clone() ?? ConfigManager.Config.Video;
ConfigManager.Config.Preferences = Preferences?.Config.Clone() ?? ConfigManager.Config.Preferences; ConfigManager.Config.Preferences = Preferences?.Config.Clone() ?? ConfigManager.Config.Preferences;
ConfigManager.Config.Emulation = Emulation?.Config.Clone() ?? ConfigManager.Config.Emulation; ConfigManager.Config.Emulation = Emulation?.Config.Clone() ?? ConfigManager.Config.Emulation;
@ -80,12 +83,13 @@ namespace Mesen.ViewModels
{ {
Audio = 0, Audio = 0,
Emulation = 1, Emulation = 1,
Video = 2, Input = 2,
Video = 3,
Nes = 4, //separator
Snes = 5, Nes = 5,
Gameboy = 6, Snes = 6,
Gameboy = 7,
Preferences = 8 //separator
Preferences = 9
} }
} }

View file

@ -8,7 +8,7 @@ namespace Mesen.ViewModels
public class EmulationConfigViewModel : DisposableViewModel public class EmulationConfigViewModel : DisposableViewModel
{ {
[Reactive] public EmulationConfig Config { get; set; } [Reactive] public EmulationConfig Config { get; set; }
public EmulationConfigViewModel() public EmulationConfigViewModel()
{ {
Config = ConfigManager.Config.Emulation.Clone(); Config = ConfigManager.Config.Emulation.Clone();
@ -19,5 +19,5 @@ namespace Mesen.ViewModels
AddDisposable(ReactiveHelper.RegisterRecursiveObserver(Config, (s, e) => { Config.ApplyConfig(); })); AddDisposable(ReactiveHelper.RegisterRecursiveObserver(Config, (s, e) => { Config.ApplyConfig(); }));
} }
} }
} }

View file

@ -0,0 +1,23 @@
using Avalonia.Controls;
using Mesen.Config;
using Mesen.Utilities;
using ReactiveUI.Fody.Helpers;
namespace Mesen.ViewModels
{
public class InputConfigViewModel : DisposableViewModel
{
[Reactive] public InputConfig Config { get; set; }
public InputConfigViewModel()
{
Config = ConfigManager.Config.Input.Clone();
if(Design.IsDesignMode) {
return;
}
AddDisposable(ReactiveHelper.RegisterRecursiveObserver(Config, (s, e) => { Config.ApplyConfig(); }));
}
}
}

View file

@ -374,6 +374,10 @@ namespace Mesen.ViewModels
ActionType = ActionType.Emulation, ActionType = ActionType.Emulation,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Emulation) OnClick = () => OpenConfig(wnd, ConfigWindowTab.Emulation)
}, },
new MainMenuAction() {
ActionType = ActionType.Input,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Input)
},
new MainMenuAction() { new MainMenuAction() {
ActionType = ActionType.Video, ActionType = ActionType.Video,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Video) OnClick = () => OpenConfig(wnd, ConfigWindowTab.Video)

View file

@ -22,15 +22,15 @@
<StackPanel> <StackPanel>
<Grid ColumnDefinitions="Auto,Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto"> <Grid ColumnDefinitions="Auto,Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Column="0" Grid.Row="0" Text="{l:Translate lblEmulationSpeed}" /> <TextBlock Grid.Column="0" Grid.Row="0" Text="{l:Translate lblEmulationSpeed}" />
<NumericUpDown Grid.Column="1" Grid.Row="0" Value="{CompiledBinding Config.EmulationSpeed}" Maximum="5000" Minimum="0" Width="80" /> <NumericUpDown Grid.Column="1" Grid.Row="0" Value="{CompiledBinding Config.EmulationSpeed}" Maximum="5000" Minimum="0" />
<TextBlock Grid.Column="2" Grid.Row="0" Text="{l:Translate lblEmuSpeedHint}" /> <TextBlock Grid.Column="2" Grid.Row="0" Text="{l:Translate lblEmuSpeedHint}" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="{l:Translate lblTurboSpeed}" /> <TextBlock Grid.Column="0" Grid.Row="1" Text="{l:Translate lblTurboSpeed}" />
<NumericUpDown Grid.Column="1" Grid.Row="1" Value="{CompiledBinding Config.TurboSpeed}" Maximum="5000" Minimum="0" Width="80" /> <NumericUpDown Grid.Column="1" Grid.Row="1" Value="{CompiledBinding Config.TurboSpeed}" Maximum="5000" Minimum="0" />
<TextBlock Grid.Column="2" Grid.Row="1" Text="{l:Translate lblTurboSpeedHint}" /> <TextBlock Grid.Column="2" Grid.Row="1" Text="{l:Translate lblTurboSpeedHint}" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="{l:Translate lblRewindSpeed}" /> <TextBlock Grid.Column="0" Grid.Row="2" Text="{l:Translate lblRewindSpeed}" />
<NumericUpDown Grid.Column="1" Grid.Row="2" Value="{CompiledBinding Config.RewindSpeed}" Maximum="5000" Minimum="0" Width="80" /> <NumericUpDown Grid.Column="1" Grid.Row="2" Value="{CompiledBinding Config.RewindSpeed}" Maximum="5000" Minimum="0" />
<TextBlock Grid.Column="2" Grid.Row="2" Text="{l:Translate lblRewindSpeedHint}" /> <TextBlock Grid.Column="2" Grid.Row="2" Text="{l:Translate lblRewindSpeedHint}" />
<TextBlock Grid.Column="0" Grid.Row="4" Text="{l:Translate lblRunAhead}" /> <TextBlock Grid.Column="0" Grid.Row="4" Text="{l:Translate lblRunAhead}" />

View file

@ -0,0 +1,89 @@
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:Mesen.ViewModels"
xmlns:c="using:Mesen.Controls"
xmlns:cfg="using:Mesen.Config"
xmlns:l="using:Mesen.Localization"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
x:DataType="vm:InputConfigViewModel"
x:Class="Mesen.Views.InputConfigView"
>
<Design.DataContext>
<vm:InputConfigViewModel />
</Design.DataContext>
<TabControl TabStripPlacement="Top" SelectedIndex="0">
<TabItem Header="{l:Translate tpgGeneral}">
<StackPanel>
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Text="{l:Translate lblDeadzone}" VerticalAlignment="Top" Margin="0 15 5 0" />
<c:MesenSlider
Margin="12 15 10 0"
HorizontalAlignment="Left"
Grid.Row="0"
Grid.Column="1"
Minimum="0"
Maximum="4"
TickFrequency="1"
Width="100"
HideValue="True"
Value="{CompiledBinding Config.ControllerDeadzoneSize}"
/>
<Grid Grid.Row="1" Grid.Column="1" RowDefinitions="Auto" ColumnDefinitions="Auto,*,Auto" Width="115" HorizontalAlignment="Left" Margin="5 -5 5 0">
<TextBlock Text="{l:Translate lblSmall}" />
<TextBlock Text="{l:Translate lblLarge}" Grid.Column="2" />
</Grid>
<TextBlock Grid.Row="2" Text="{l:Translate lblSensitivity}" VerticalAlignment="Top" Margin="0 15 5 0" />
<c:MesenSlider
Margin="12 15 10 0"
HorizontalAlignment="Left"
Grid.Row="2"
Grid.Column="1"
Minimum="0"
Maximum="3"
TickFrequency="1"
Width="100"
HideValue="True"
Value="{CompiledBinding Config.MouseSensitivity}"
/>
<Grid Grid.Row="3" Grid.Column="1" RowDefinitions="Auto" ColumnDefinitions="Auto,*,Auto" Width="107" HorizontalAlignment="Left" Margin="10 -5 5 0">
<TextBlock Text="{l:Translate lblLow}" />
<TextBlock Text="{l:Translate lblHigh}" Grid.Column="2" />
</Grid>
</Grid>
</StackPanel>
</TabItem>
<TabItem Header="{l:Translate tpgDisplay}">
<Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto">
<TextBlock Text="{l:Translate lblDisplayInputPorts}" VerticalAlignment="Top" Margin="0 5 0 0" />
<Grid Grid.Column="1" ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto">
<Grid.Styles>
<Style Selector="CheckBox">
<Setter Property="Margin" Value="0 0 5 0" />
</Style>
</Grid.Styles>
<CheckBox Content="{l:Translate chkDisplayPort1}" IsChecked="{CompiledBinding Config.DisplayInputPort1}" />
<CheckBox Grid.Column="1" Content="{l:Translate chkDisplayPort2}" IsChecked="{CompiledBinding Config.DisplayInputPort2}" />
<CheckBox Grid.Row="1" Content="{l:Translate chkDisplayPort3}" IsChecked="{CompiledBinding Config.DisplayInputPort3}" />
<CheckBox Grid.Row="1" Grid.Column="1" Content="{l:Translate chkDisplayPort4}" IsChecked="{CompiledBinding Config.DisplayInputPort4}" />
<CheckBox Grid.Row="2" Content="{l:Translate chkDisplayPort5}" IsChecked="{CompiledBinding Config.DisplayInputPort5}" />
</Grid>
<TextBlock Grid.Row="1" Text="{l:Translate lblDisplayPosition}" />
<c:EnumComboBox Grid.Row="1" Grid.Column="1" SelectedItem="{CompiledBinding Config.DisplayInputPosition}" />
<CheckBox Grid.Row="2" Grid.ColumnSpan="2" IsChecked="{CompiledBinding Config.DisplayInputHorizontally}" Content="{l:Translate chkDisplayInputHorizontally}" />
</Grid>
</TabItem>
</TabControl>
</UserControl>

View file

@ -0,0 +1,21 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Mesen.Utilities;
using Mesen.Config;
namespace Mesen.Views
{
public class InputConfigView : UserControl
{
public InputConfigView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View file

@ -26,6 +26,9 @@
<DataTemplate DataType="{x:Type vm:EmulationConfigViewModel}"> <DataTemplate DataType="{x:Type vm:EmulationConfigViewModel}">
<v:EmulationConfigView /> <v:EmulationConfigView />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type vm:InputConfigViewModel}">
<v:InputConfigView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:VideoConfigViewModel}"> <DataTemplate DataType="{x:Type vm:VideoConfigViewModel}">
<v:VideoConfigView /> <v:VideoConfigView />
</DataTemplate> </DataTemplate>
@ -71,6 +74,14 @@
</StackPanel> </StackPanel>
</TabItem.Header> </TabItem.Header>
</TabItem> </TabItem>
<TabItem Content="{CompiledBinding Input}">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="/Assets/Controller.png" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center" Text="{l:Translate tabInput}" />
</StackPanel>
</TabItem.Header>
</TabItem>
<TabItem Content="{CompiledBinding Video}"> <TabItem Content="{CompiledBinding Video}">
<TabItem.Header> <TabItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">

View file

@ -120,14 +120,6 @@ void Renderer::CleanupDevice()
{ {
ResetNesBuffers(); ResetNesBuffers();
ReleaseRenderTargetView(); ReleaseRenderTargetView();
if(_pAlphaEnableBlendingState) {
_pAlphaEnableBlendingState->Release();
_pAlphaEnableBlendingState = nullptr;
}
if(_pDepthDisabledStencilState) {
_pDepthDisabledStencilState->Release();
_pDepthDisabledStencilState = nullptr;
}
if(_pSwapChain) { if(_pSwapChain) {
_pSwapChain->SetFullscreenState(false, nullptr); _pSwapChain->SetFullscreenState(false, nullptr);
_pSwapChain->Release(); _pSwapChain->Release();
@ -318,61 +310,6 @@ HRESULT Renderer::InitDevice()
if(FAILED(hr)) { if(FAILED(hr)) {
return hr; return hr;
} }
D3D11_DEPTH_STENCIL_DESC depthDisabledStencilDesc;
ZeroMemory(&depthDisabledStencilDesc, sizeof(depthDisabledStencilDesc));
depthDisabledStencilDesc.DepthEnable = false;
depthDisabledStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthDisabledStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
depthDisabledStencilDesc.StencilEnable = true;
depthDisabledStencilDesc.StencilReadMask = 0xFF;
depthDisabledStencilDesc.StencilWriteMask = 0xFF;
depthDisabledStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthDisabledStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthDisabledStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
depthDisabledStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthDisabledStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
depthDisabledStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthDisabledStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create the state using the device.
hr = _pd3dDevice->CreateDepthStencilState(&depthDisabledStencilDesc, &_pDepthDisabledStencilState);
if(FAILED(hr)) {
MessageManager::Log("D3DDevice::CreateDepthStencilState() failed - Error:" + std::to_string(hr));
return hr;
}
// Clear the blend state description.
D3D11_BLEND_DESC blendStateDescription;
ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));
// Create an alpha enabled blend state description.
blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].RenderTargetWriteMask = 0x0f;
// Create the blend state using the description.
hr = _pd3dDevice->CreateBlendState(&blendStateDescription, &_pAlphaEnableBlendingState);
if(FAILED(hr)) {
MessageManager::Log("D3DDevice::CreateBlendState() failed - Error:" + std::to_string(hr));
return hr;
}
float blendFactor[4];
blendFactor[0] = 0.0f;
blendFactor[1] = 0.0f;
blendFactor[2] = 0.0f;
blendFactor[3] = 0.0f;
_pDeviceContext->OMSetBlendState(_pAlphaEnableBlendingState, blendFactor, 0xffffffff);
_pDeviceContext->OMSetDepthStencilState(_pDepthDisabledStencilState, 1);
hr = CreateEmuTextureBuffers(); hr = CreateEmuTextureBuffers();
if(FAILED(hr)) { if(FAILED(hr)) {
return hr; return hr;
@ -420,7 +357,7 @@ ID3D11ShaderResourceView* Renderer::GetShaderResourceView(ID3D11Texture2D* textu
return shaderResourceView; return shaderResourceView;
} }
void Renderer::UpdateFrame(RenderedFrame frame) void Renderer::UpdateFrame(RenderedFrame& frame)
{ {
SetScreenSize(frame.Width, frame.Height); SetScreenSize(frame.Width, frame.Height);

View file

@ -25,8 +25,6 @@ private:
ID3D11DeviceContext* _pDeviceContext = nullptr; ID3D11DeviceContext* _pDeviceContext = nullptr;
IDXGISwapChain* _pSwapChain = nullptr; IDXGISwapChain* _pSwapChain = nullptr;
ID3D11RenderTargetView* _pRenderTargetView = nullptr; ID3D11RenderTargetView* _pRenderTargetView = nullptr;
ID3D11DepthStencilState* _pDepthDisabledStencilState = nullptr;
ID3D11BlendState* _pAlphaEnableBlendingState = nullptr;
atomic<bool> _needFlip = false; atomic<bool> _needFlip = false;
uint8_t* _textureBuffer[2] = { nullptr, nullptr }; uint8_t* _textureBuffer[2] = { nullptr, nullptr };
@ -86,5 +84,5 @@ public:
void Reset(); void Reset();
void Render(uint32_t* hudBuffer, uint32_t hudWidth, uint32_t hudHeight); void Render(uint32_t* hudBuffer, uint32_t hudWidth, uint32_t hudHeight);
void UpdateFrame(RenderedFrame frame); void UpdateFrame(RenderedFrame& frame);
}; };