Input: Added Super Scope support

This commit is contained in:
Sour 2019-08-09 20:47:12 -04:00
parent ed4a0e60e8
commit da5e77d6e3
11 changed files with 177 additions and 7 deletions

View file

@ -11,6 +11,7 @@
#include "SnesController.h"
#include "SnesMouse.h"
#include "Multitap.h"
#include "SuperScope.h"
#include "EventType.h"
#include "../Utilities/Serializer.h"
@ -110,7 +111,7 @@ shared_ptr<BaseControlDevice> ControlManager::CreateControllerDevice(ControllerT
case ControllerType::None: break;
case ControllerType::SnesController: device.reset(new SnesController(console, port, cfg.Controllers[port].Keys)); break;
case ControllerType::SnesMouse: device.reset(new SnesMouse(console, port)); break;
case ControllerType::SuperScope: break;
case ControllerType::SuperScope: device.reset(new SuperScope(console, port, cfg.Controllers[port].Keys)); break;
case ControllerType::Multitap: device.reset(new Multitap(console, port, cfg.Controllers[port].Keys, cfg.Controllers[2].Keys, cfg.Controllers[3].Keys, cfg.Controllers[4].Keys)); break;
}

View file

@ -171,6 +171,7 @@
<ClInclude Include="SPC_DSP.h" />
<ClInclude Include="SPC_Filter.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="SuperScope.h" />
<ClInclude Include="SystemActionManager.h" />
<ClInclude Include="TraceLogger.h" />
<ClInclude Include="VideoDecoder.h" />

View file

@ -398,6 +398,9 @@
<ClInclude Include="FrameLimiter.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="SuperScope.h">
<Filter>SNES\Input</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />

View file

@ -102,9 +102,9 @@ void KeyManager::SetMousePosition(shared_ptr<Console> console, double x, double
_mousePosition.Y = -1;
} else {
OverscanDimensions overscan = console->GetSettings()->GetOverscan();
ScreenSize size = console->GetVideoDecoder()->GetScreenSize(false);
_mousePosition.X = (int32_t)(x*size.Width/2 + overscan.Left);
_mousePosition.Y = (int32_t)(y*size.Height/2 + overscan.Top);
ScreenSize size = console->GetVideoDecoder()->GetScreenSize(true);
_mousePosition.X = (int32_t)(x*size.Width + overscan.Left);
_mousePosition.Y = (int32_t)(y*size.Height + overscan.Top);
}
}

View file

@ -441,6 +441,9 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock)
_scanline++;
if(_scanline == _nmiScanline) {
ProcessLocationLatchRequest();
_latchRequest = false;
//Reset OAM address at the start of vblank?
if(!_forcedVblank) {
//TODO, the timing of this may be slightly off? should happen at H=10 based on anomie's docs
@ -1566,6 +1569,29 @@ bool Ppu::IsDoubleWidth()
return _hiResMode || _bgMode == 5 || _bgMode == 6;
}
void Ppu::SetLocationLatchRequest(uint16_t x, uint16_t y)
{
//Used by super scope
_latchRequest = true;
_latchRequestX = x;
_latchRequestY = y;
}
void Ppu::ProcessLocationLatchRequest()
{
//Used by super scope
if(_latchRequest) {
uint16_t cycle = GetCycle();
uint16_t scanline = GetRealScanline();
if(scanline > _latchRequestY || (_latchRequestY == scanline && cycle >= _latchRequestX)) {
_latchRequest = false;
_horizontalLocation = _latchRequestX;
_verticalLocation = _latchRequestY;
_locationLatched = true;
}
}
}
void Ppu::LatchLocationValues()
{
_horizontalLocation = GetCycle();
@ -1699,6 +1725,8 @@ uint8_t Ppu::Read(uint16_t addr)
case 0x213C: {
//OPHCT - Horizontal Scanline Location
ProcessLocationLatchRequest();
uint8_t value;
if(_horizontalLocToggle) {
//"Note that the value read is only 9 bits: bits 1-7 of the high byte are PPU2 Open Bus."
@ -1713,6 +1741,8 @@ uint8_t Ppu::Read(uint16_t addr)
case 0x213D: {
//OPVCT - Vertical Scanline Location
ProcessLocationLatchRequest();
uint8_t value;
if(_verticalLocationToggle) {
//"Note that the value read is only 9 bits: bits 1-7 of the high byte are PPU2 Open Bus."
@ -1739,6 +1769,8 @@ uint8_t Ppu::Read(uint16_t addr)
case 0x213F: {
//STAT78 - PPU Status Flag and Version
ProcessLocationLatchRequest();
uint8_t value = (
(_oddFrame ? 0x80 : 0) |
(_locationLatched ? 0x40 : 0) |

View file

@ -149,6 +149,9 @@ private:
uint16_t _verticalLocation = 0;
bool _verticalLocationToggle = false;
bool _locationLatched = false;
bool _latchRequest = false;
uint16_t _latchRequestX = 0;
uint16_t _latchRequestY = 0;
Timer _frameSkipTimer;
bool _skipRender = false;
@ -278,6 +281,8 @@ public:
uint8_t* GetCgRam();
uint8_t* GetSpriteRam();
void SetLocationLatchRequest(uint16_t x, uint16_t y);
void ProcessLocationLatchRequest();
void LatchLocationValues();
uint8_t Read(uint16_t addr);

121
Core/SuperScope.h Normal file
View file

@ -0,0 +1,121 @@
#pragma once
#include "stdafx.h"
#include "BaseControlDevice.h"
#include "KeyManager.h"
#include "Ppu.h"
#include "../Utilities/Serializer.h"
class SuperScope : public BaseControlDevice
{
private:
enum Buttons { Fire = 0, Cursor = 1, Turbo = 2, Pause = 3 };
uint32_t _stateBuffer = 0;
bool _prevFireButton = false;
bool _prevTurboButton = false;
bool _prevPauseButton = false;
bool _turbo = false;
Ppu *_ppu;
protected:
bool HasCoordinates() override { return true; }
string GetKeyNames() override
{
return "FCTP";
}
void InternalSetStateFromInput() override
{
SetPressedState(Buttons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
SetPressedState(Buttons::Cursor, KeyManager::IsMouseButtonPressed(MouseButton::RightButton));
SetPressedState(Buttons::Turbo, KeyManager::IsMouseButtonPressed(MouseButton::MiddleButton));
for(KeyMapping keyMapping : _keyMappings) {
SetPressedState(Buttons::Pause, KeyManager::IsKeyPressed(keyMapping.Start));
}
MousePosition pos = KeyManager::GetMousePosition();
SetCoordinates(pos);
}
void OnAfterSetState() override
{
MousePosition pos = GetCoordinates();
//Make the PPU latch the H/V counters at the mouse's position (offset slightly to make target in the center of the mouse cursor)
if(pos.X >= 0 && pos.Y >= 0) {
_ppu->SetLocationLatchRequest(pos.X + 10, std::max(0, pos.Y - 3));
}
}
void Serialize(Serializer &s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_stateBuffer, _prevTurboButton, _prevFireButton, _prevPauseButton, _turbo);
}
void RefreshStateBuffer() override
{
_stateBuffer = (uint32_t)ToByte();
_prevFireButton = IsPressed(Buttons::Fire);
_prevTurboButton = IsPressed(Buttons::Turbo);
_prevPauseButton = IsPressed(Buttons::Pause);
}
uint16_t ToByte()
{
uint16_t output = 0xFF00; //signature bits
if(!_prevTurboButton && IsPressed(Buttons::Turbo)) {
_turbo = !_turbo;
}
if((_turbo || !_prevFireButton) && IsPressed(Buttons::Fire)) {
output |= 0x01;
}
if(IsPressed(Buttons::Cursor)) {
output |= 0x02;
}
if(_turbo) {
output |= 0x04;
}
if(!_prevPauseButton && IsPressed(Buttons::Pause)) {
output |= 0x08;
}
if(GetCoordinates().X < 0 || GetCoordinates().Y < 0) {
output |= 0x40; //offscreen flag
}
return output;
}
public:
SuperScope(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console, port, keyMappings)
{
_ppu = console->GetPpu().get();
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(IsCurrentPort(addr)) {
StrobeProcessRead();
output = (_stateBuffer & 0x01);
_stateBuffer >>= 1;
_stateBuffer |= 0x8000;
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

View file

@ -21,6 +21,7 @@
#define DEVICE_AUTO RETRO_DEVICE_JOYPAD
#define DEVICE_GAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0)
#define DEVICE_MULTITAP RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1)
#define DEVICE_SUPERSCOPE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_POINTER, 0)
#define DEVICE_SNESMOUSE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 2)
static retro_log_printf_t logCallback = nullptr;
@ -124,6 +125,7 @@ extern "C" {
{ "None", DEVICE_NONE },
{ "SNES Controller", DEVICE_GAMEPAD },
{ "SNES Mouse", DEVICE_SNESMOUSE },
{ "Super Scope", DEVICE_SUPERSCOPE },
{ "Multitap", DEVICE_MULTITAP },
{ NULL, 0 },
};
@ -145,7 +147,7 @@ extern "C" {
static constexpr struct retro_controller_info ports[] = {
{ pads1, 3 },
{ pads2, 4 },
{ pads2, 5 },
{ pads3, 1 },
{ pads4, 1 },
{ pads5, 1 },
@ -468,7 +470,10 @@ extern "C" {
if(device == DEVICE_AUTO) {
if(port <= 4) {
switch(_console->GetSettings()->GetInputConfig().Controllers[port].Type) {
case ControllerType::Multitap:
case ControllerType::SnesController: device = DEVICE_GAMEPAD; break;
case ControllerType::SuperScope: device = DEVICE_SUPERSCOPE; break;
case ControllerType::SnesMouse: device = DEVICE_SNESMOUSE; break;
default: return;
}
@ -513,6 +518,7 @@ extern "C" {
case DEVICE_GAMEPAD: type = ControllerType::SnesController; break;
case DEVICE_MULTITAP: type = ControllerType::Multitap; break;
case DEVICE_SNESMOUSE: type = ControllerType::SnesMouse; break;
case DEVICE_SUPERSCOPE: type = ControllerType::SuperScope; break;
}
input.Controllers[port].Type = type;
}

View file

@ -851,6 +851,7 @@
<Value ID="SnesController">SNES Controller</Value>
<Value ID="SnesMouse">SNES Mouse</Value>
<Value ID="SuperScope">Super Scope</Value>
<Value ID="Multitap">Super Multitap</Value>
</Enum>
<Enum ID="VideoAspectRatio">
<Value ID="NoStretching">Default (No Stretching)</Value>

View file

@ -98,7 +98,7 @@ namespace Mesen.GUI.Emulation
public static bool NeedMouseIcon
{
get { return false; }
get { return IsLightGun; }
}
public static void OnMouseMove(Control ctrl)

View file

@ -24,7 +24,7 @@ namespace Mesen.GUI.Forms.Config
Entity = cfg;
BaseConfigForm.InitializeComboBox((ComboBox)cboPlayer1, typeof(ControllerType), ControllerType.SuperScope);
BaseConfigForm.InitializeComboBox((ComboBox)cboPlayer2, typeof(ControllerType), ControllerType.SuperScope);
BaseConfigForm.InitializeComboBox((ComboBox)cboPlayer2, typeof(ControllerType));
BaseConfigForm.InitializeComboBox((ComboBox)cboMultitap1, typeof(ControllerType), ControllerType.None, ControllerType.Multitap, ControllerType.SnesMouse, ControllerType.SuperScope);
BaseConfigForm.InitializeComboBox((ComboBox)cboMultitap2, typeof(ControllerType), ControllerType.None, ControllerType.Multitap, ControllerType.SnesMouse, ControllerType.SuperScope);