diff --git a/Core/Console.cpp b/Core/Console.cpp index caa5abc2..0e1eab98 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -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; } } diff --git a/Core/Console.h b/Core/Console.h index 84f2f9b9..8ce92969 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -7,9 +7,16 @@ #include "MemoryManager.h" #include "ControlManager.h" +enum EmulationFlags +{ + LimitFPS = 0x01, +}; + class Console { private: + static uint32_t Flags; + unique_ptr _cpu; unique_ptr _ppu; unique_ptr _mapper; @@ -17,7 +24,6 @@ class Console unique_ptr _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); }; diff --git a/Core/ControlManager.cpp b/Core/ControlManager.cpp index f91ca604..349bc074 100644 --- a/Core/ControlManager.cpp +++ b/Core/ControlManager.cpp @@ -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 { diff --git a/Core/stdafx.h b/Core/stdafx.h index 0821ece0..b0264d1f 100644 --- a/Core/stdafx.h +++ b/Core/stdafx.h @@ -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; diff --git a/GUI/GUI.rc b/GUI/GUI.rc index d927192d..9cc6d918 100644 Binary files a/GUI/GUI.rc and b/GUI/GUI.rc differ diff --git a/GUI/GUI.vcxproj b/GUI/GUI.vcxproj index b34b3ff8..838073ce 100644 --- a/GUI/GUI.vcxproj +++ b/GUI/GUI.vcxproj @@ -59,7 +59,7 @@ Windows true - 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) + 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) @@ -89,7 +89,7 @@ true true true - 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) + 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) @@ -113,6 +113,7 @@ + @@ -121,6 +122,7 @@ + diff --git a/GUI/GUI.vcxproj.filters b/GUI/GUI.vcxproj.filters index 89040aa1..32ed1c6e 100644 --- a/GUI/GUI.vcxproj.filters +++ b/GUI/GUI.vcxproj.filters @@ -57,9 +57,6 @@ Header Files\DirectXTK - - Header Files\DirectXTK - Header Files\DirectXTK @@ -84,6 +81,12 @@ Header Files + + Header Files + + + Header Files + @@ -101,6 +104,9 @@ Source Files + + Source Files + diff --git a/GUI/GamePad.cpp b/GUI/GamePad.cpp new file mode 100644 index 00000000..8736466c --- /dev/null +++ b/GUI/GamePad.cpp @@ -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; +} diff --git a/GUI/GamePad.h b/GUI/GamePad.h new file mode 100644 index 00000000..37f6c4e0 --- /dev/null +++ b/GUI/GamePad.h @@ -0,0 +1,17 @@ +#pragma once + +#include "stdafx.h" +#include + +class GamePad +{ + private: + XINPUT_STATE _state; + + bool Initialize(); + + public: + GamePad(); + + bool IsPressed(WORD button); +}; diff --git a/GUI/InputManager.cpp b/GUI/InputManager.cpp index ef6169f3..a0af5202 100644 --- a/GUI/InputManager.cpp +++ b/GUI/InputManager.cpp @@ -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; -} \ No newline at end of file +} diff --git a/GUI/InputManager.h b/GUI/InputManager.h index 4c87872f..c6cecd26 100644 --- a/GUI/InputManager.h +++ b/GUI/InputManager.h @@ -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: diff --git a/GUI/MainWindow.cpp b/GUI/MainWindow.cpp index 37ff2605..0693bbcb 100644 --- a/GUI/MainWindow.cpp +++ b/GUI/MainWindow.cpp @@ -1,7 +1,5 @@ #include "stdafx.h" -#include -#include -#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)) { - TranslateMessage(&msg); - DispatchMessage(&msg); + 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(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; diff --git a/GUI/MainWindow.h b/GUI/MainWindow.h index 109dd153..a3c39714 100644 --- a/GUI/MainWindow.h +++ b/GUI/MainWindow.h @@ -12,6 +12,7 @@ namespace NES { int _nCmdShow; Renderer _renderer; unique_ptr _console; + unique_ptr _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) { diff --git a/GUI/Renderer.cpp b/GUI/Renderer.cpp index fee91bbc..8fffb8b5 100644 --- a/GUI/Renderer.cpp +++ b/GUI/Renderer.cpp @@ -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 diff --git a/GUI/resource.h b/GUI/resource.h index 94ae42e6..229aaea4 100644 Binary files a/GUI/resource.h and b/GUI/resource.h differ diff --git a/GUI/stdafx.h b/GUI/stdafx.h index 1b21069f..90a5a406 100644 --- a/GUI/stdafx.h +++ b/GUI/stdafx.h @@ -28,5 +28,10 @@ #include #include #include +#include +#include +#include + +using std::thread; // TODO: reference additional headers your program requires here