UI improvements + Gamepad support

This commit is contained in:
Souryo 2014-06-21 19:03:13 -04:00
parent 1765b9a690
commit 9ada341050
16 changed files with 169 additions and 45 deletions

View File

@ -2,6 +2,8 @@
#include "Console.h"
#include "Timer.h"
uint32_t Console::Flags = 0;
Console::Console(wstring filename)
{
_mapper = MapperFactory::InitializeFromFile(filename);
@ -30,7 +32,21 @@ void Console::Reset()
void Console::Stop()
{
_stop = true;
while(!_stopped) { }
}
void Console::SetFlags(int flags)
{
Console::Flags |= flags;
}
void Console::ClearFlags(int flags)
{
Console::Flags ^= flags;
}
bool Console::CheckFlag(int flag)
{
return (Console::Flags & flag) == flag;
}
void Console::Run()
@ -45,7 +61,7 @@ void Console::Run()
executedCycles += _cpu->Exec();
_ppu->Exec();
if(limitFrameRate && executedCycles > 30000) {
if(CheckFlag(EmulationFlags::LimitFPS) && executedCycles > 30000) {
double targetTime = 16.77;
elapsedTime = clockTimer.GetElapsedMS();
while(targetTime > elapsedTime) {
@ -66,7 +82,6 @@ void Console::Run()
}
if(_stop) {
_stopped = true;
break;
}
}

View File

@ -7,9 +7,16 @@
#include "MemoryManager.h"
#include "ControlManager.h"
enum EmulationFlags
{
LimitFPS = 0x01,
};
class Console
{
private:
static uint32_t Flags;
unique_ptr<CPU> _cpu;
unique_ptr<PPU> _ppu;
unique_ptr<BaseMapper> _mapper;
@ -17,7 +24,6 @@ class Console
unique_ptr<MemoryManager> _memoryManager;
bool _stop = false;
bool _stopped = false;
public:
Console(wstring filename);
@ -26,6 +32,11 @@ class Console
void Stop();
void RunTest(bool callback(Console*));
void Reset();
static bool CheckFlag(int flag);
static void SetFlags(int flags);
static void ClearFlags(int flags);
static void RunTests();
static void Load(wstring filename);
};

View File

@ -33,8 +33,8 @@ void ControlManager::RefreshStateBuffer(uint8_t port)
ButtonState buttonState = controlDevice->GetButtonState();
//"Button status for each controller is returned as an 8-bit report in the following order: A, B, Select, Start, Up, Down, Left, Right."
uint8_t state = buttonState.A | (buttonState.B << 1) | (buttonState.Select << 2) | (buttonState.Start << 3) |
(buttonState.Up << 4) | (buttonState.Down << 5) | (buttonState.Left << 6) | (buttonState.Right << 7);
uint8_t state = (uint8_t)buttonState.A | ((uint8_t)buttonState.B << 1) | ((uint8_t)buttonState.Select << 2) | ((uint8_t)buttonState.Start << 3) |
((uint8_t)buttonState.Up << 4) | ((uint8_t)buttonState.Down << 5) | ((uint8_t)buttonState.Left << 6) | ((uint8_t)buttonState.Right << 7);
_stateBuffer[port] = state;
} else {

View File

@ -32,7 +32,6 @@ using std::shared_ptr;
using std::unique_ptr;
using std::ios;
using std::ifstream;
//using std::string;
using std::wstring;
using std::exception;
using std::atomic;

Binary file not shown.

View File

@ -59,7 +59,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OptimizeReferences>
</OptimizeReferences>
<EnableCOMDATFolding>
@ -89,7 +89,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<FxCompile>
<ShaderType>
@ -113,6 +113,7 @@
<ClInclude Include="DirectXTK\VertexTypes.h" />
<ClInclude Include="DirectXTK\WICTextureLoader.h" />
<ClInclude Include="DirectXTK\XboxDDSTextureLoader.h" />
<ClInclude Include="GamePad.h" />
<ClInclude Include="InputManager.h" />
<ClInclude Include="Renderer.h" />
<ClInclude Include="Resource.h" />
@ -121,6 +122,7 @@
<ClInclude Include="MainWindow.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="GamePad.cpp" />
<ClCompile Include="InputManager.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="Renderer.cpp" />

View File

@ -57,9 +57,6 @@
<ClInclude Include="DirectXTK\PrimitiveBatch.h">
<Filter>Header Files\DirectXTK</Filter>
</ClInclude>
<ClInclude Include="Resource.h">
<Filter>Header Files\DirectXTK</Filter>
</ClInclude>
<ClInclude Include="DirectXTK\ScreenGrab.h">
<Filter>Header Files\DirectXTK</Filter>
</ClInclude>
@ -84,6 +81,12 @@
<ClInclude Include="InputManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GamePad.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -101,6 +104,9 @@
<ClCompile Include="InputManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GamePad.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GUI.rc">

27
GUI/GamePad.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "stdafx.h"
#include "GamePad.h"
GamePad::GamePad()
{
}
bool GamePad::Initialize()
{
int controllerId = -1;
for(DWORD i = 0; i < XUSER_MAX_COUNT && controllerId == -1; i++) {
ZeroMemory(&_state, sizeof(XINPUT_STATE));
if(XInputGetState(i, &_state) == ERROR_SUCCESS) {
controllerId = i;
}
}
return controllerId != -1;
}
bool GamePad::IsPressed(WORD button)
{
Initialize();
return (_state.Gamepad.wButtons & button) != 0;
}

17
GUI/GamePad.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "stdafx.h"
#include <Xinput.h>
class GamePad
{
private:
XINPUT_STATE _state;
bool Initialize();
public:
GamePad();
bool IsPressed(WORD button);
};

View File

@ -9,14 +9,14 @@ bool InputManager::IsKeyPressed(int key)
ButtonState InputManager::GetButtonState()
{
ButtonState state;
state.A = IsKeyPressed('A');
state.B = IsKeyPressed('S');
state.Select = IsKeyPressed('W');
state.Start = IsKeyPressed('Q');
state.Up = IsKeyPressed(VK_UP);
state.Down = IsKeyPressed(VK_DOWN);
state.Left = IsKeyPressed(VK_LEFT);
state.Right = IsKeyPressed(VK_RIGHT);
state.A = IsKeyPressed('A') || _gamePad.IsPressed(XINPUT_GAMEPAD_X);
state.B = IsKeyPressed('S') || _gamePad.IsPressed(XINPUT_GAMEPAD_A);
state.Select = IsKeyPressed('W') || _gamePad.IsPressed(XINPUT_GAMEPAD_BACK);
state.Start = IsKeyPressed('Q') || _gamePad.IsPressed(XINPUT_GAMEPAD_START);
state.Up = IsKeyPressed(VK_UP) || _gamePad.IsPressed(XINPUT_GAMEPAD_DPAD_UP);
state.Down = IsKeyPressed(VK_DOWN) || _gamePad.IsPressed(XINPUT_GAMEPAD_DPAD_DOWN);
state.Left = IsKeyPressed(VK_LEFT) || _gamePad.IsPressed(XINPUT_GAMEPAD_DPAD_LEFT);
state.Right = IsKeyPressed(VK_RIGHT) || _gamePad.IsPressed(XINPUT_GAMEPAD_DPAD_RIGHT);
return state;
}

View File

@ -2,10 +2,13 @@
#include "stdafx.h"
#include "..\Core\IControlDevice.h"
#include "GamePad.h"
class InputManager : public IControlDevice
{
private:
GamePad _gamePad;
bool IsKeyPressed(int key);
public:

View File

@ -1,7 +1,5 @@
#include "stdafx.h"
#include <io.h>
#include <Fcntl.h>
#include "resource.h"
#include "Resource.h"
#include "MainWindow.h"
#include "..\Core\Console.h"
#include "..\Core\Timer.h"
@ -68,25 +66,23 @@ namespace NES
Initialize();
InputManager inputManager;
ControlManager::RegisterControlDevice(&inputManager, 0);
HACCEL hAccel = LoadAccelerators(_hInstance, MAKEINTRESOURCE(IDC_Accelerator));
if(hAccel == nullptr) {
//error
std::cout << "error";
}
MSG msg = { 0 };
Timer timer;
int frameCount = 0;
while(WM_QUIT != msg.message) {
if(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if(!TranslateAccelerator(_hWnd, hAccel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} else {
_renderer.Render();
frameCount++;
if(frameCount == 500) {
double fps = (double)frameCount / (timer.GetElapsedMS() / 1000);
//std::cout << "FPS: " << fps << std::endl;
timer.Reset();
frameCount = 0;
}
}
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(1));
}
@ -177,8 +173,7 @@ namespace NES
Stop();
_console.reset(new Console(filename));
std::thread nesThread(&Console::Run, _console.get());
nesThread.detach();
_emuThread.reset(new thread(&Console::Run, _console.get()));
}
}
@ -186,12 +181,32 @@ namespace NES
{
if(_console) {
_console->Stop();
_emuThread->join();
_console.release();
}
}
bool MainWindow::ToggleMenuCheck(int resourceID)
{
HMENU hMenu = GetMenu(_hWnd);
bool checked = (GetMenuState(hMenu, resourceID, MF_BYCOMMAND) & MF_CHECKED) == MF_CHECKED;
CheckMenuItem(hMenu, resourceID, MF_BYCOMMAND | (checked ? MF_UNCHECKED : MF_CHECKED));
return !checked;
}
void MainWindow::LimitFPS_Click()
{
if(ToggleMenuCheck(ID_OPTIONS_LIMITFPS)) {
Console::SetFlags(EmulationFlags::LimitFPS);
} else {
Console::ClearFlags(EmulationFlags::LimitFPS);
}
}
LRESULT CALLBACK MainWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static MainWindow *mainWindow = MainWindow::GetInstance();
PAINTSTRUCT ps;
int wmId, wmEvent;
HDC hdc;
@ -201,13 +216,15 @@ namespace NES
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
switch (wmId) {
case IDM_FILE_OPEN:
MainWindow::GetInstance()->OpenROM();
mainWindow->OpenROM();
break;
case IDM_FILE_RUNTESTS:
break;
case ID_OPTIONS_LIMITFPS:
mainWindow->LimitFPS_Click();
break;
case IDM_ABOUT:
DialogBox(nullptr, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
@ -224,8 +241,25 @@ namespace NES
EndPaint(hWnd, &ps);
break;
case WM_WINDOWPOSCHANGING:
WINDOWPOS* windowPos;
windowPos = (WINDOWPOS*)lParam;
RECT clientRect;
RECT windowRect;
LONG xGap;
LONG yGap;
GetWindowRect(hWnd, &windowRect);
GetClientRect(hWnd, &clientRect);
xGap = (windowRect.right - windowRect.left) - (clientRect.right - clientRect.left);
yGap = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
windowPos->cy = (windowPos->cx - xGap) * 240 / 256 + yGap;
break;
case WM_DESTROY:
MainWindow::GetInstance()->Stop();
mainWindow->Stop();
PostQuitMessage(0);
break;

View File

@ -12,6 +12,7 @@ namespace NES {
int _nCmdShow;
Renderer _renderer;
unique_ptr<Console> _console;
unique_ptr<thread> _emuThread;
bool Initialize();
HRESULT InitWindow();
@ -23,6 +24,10 @@ namespace NES {
return MainWindow::Instance;
}
void LimitFPS_Click();
bool ToggleMenuCheck(int resourceID);
public:
MainWindow(HINSTANCE hInstance, int nCmdShow) : _hInstance(hInstance), _nCmdShow(nCmdShow)
{

View File

@ -28,8 +28,8 @@ namespace NES
RECT rc;
GetClientRect(_hWnd, &rc);
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT width = 256; // rc.right - rc.left;
UINT height = 240; // rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG

Binary file not shown.

View File

@ -28,5 +28,10 @@
#include <d3dcompiler.h>
#include <directxmath.h>
#include <directxcolors.h>
#include <io.h>
#include <Fcntl.h>
#include <thread>
using std::thread;
// TODO: reference additional headers your program requires here