diff --git a/Core/Console.cpp b/Core/Console.cpp index baf3d822..7e421f2e 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -46,7 +46,7 @@ void Console::SetFlags(int flags) void Console::ClearFlags(int flags) { - Console::Flags ^= flags; + Console::Flags &= ~flags; } bool Console::CheckFlag(int flag) diff --git a/GUI/GUI.rc b/GUI/GUI.rc index f26022f6..64173e4c 100644 Binary files a/GUI/GUI.rc and b/GUI/GUI.rc differ diff --git a/GUI/MainWindow.cpp b/GUI/MainWindow.cpp index d321c1ea..62dae742 100644 --- a/GUI/MainWindow.cpp +++ b/GUI/MainWindow.cpp @@ -194,16 +194,25 @@ namespace NES { SetMenuEnabled(ID_NES_RESET, true); SetMenuEnabled(ID_NES_STOP, true); SetMenuEnabled(ID_NES_RESUME, false); + + _renderer->ClearFlags(UIFlags::ShowPauseScreen); + if(IsMenuChecked(ID_OPTIONS_SHOWFPS)) { + _renderer->SetFlags(UIFlags::ShowFPS); + } } } void MainWindow::Stop(bool powerOff) { + _renderer->ClearFlags(UIFlags::ShowFPS | UIFlags::ShowPauseScreen); + _soundManager->Reset(); if(_console) { _console->Stop(); if(powerOff) { _console.release(); + } else { + _renderer->SetFlags(UIFlags::ShowPauseScreen); } } if(_emuThread) { @@ -258,6 +267,15 @@ namespace NES { } } + void MainWindow::ShowFPS_Click() + { + if(ToggleMenuCheck(ID_OPTIONS_SHOWFPS)) { + _renderer->SetFlags(UIFlags::ShowFPS); + } else { + _renderer->ClearFlags(UIFlags::ShowFPS); + } + } + void MainWindow::SaveTestResult() { if(_console) { @@ -361,6 +379,9 @@ namespace NES { case ID_OPTIONS_LIMITFPS: mainWindow->LimitFPS_Click(); break; + case ID_OPTIONS_SHOWFPS: + mainWindow->ShowFPS_Click(); + break; case ID_TESTS_RUNTESTS: mainWindow->RunTests(); diff --git a/GUI/MainWindow.h b/GUI/MainWindow.h index 12cc985a..d146a8a0 100644 --- a/GUI/MainWindow.h +++ b/GUI/MainWindow.h @@ -31,6 +31,7 @@ namespace NES { vector GetFilesInFolder(wstring folderMask); void LimitFPS_Click(); + void ShowFPS_Click(); void SetMenuEnabled(int resourceID, bool enabled); diff --git a/GUI/Renderer.cpp b/GUI/Renderer.cpp index 066fa68c..46a48f4c 100644 --- a/GUI/Renderer.cpp +++ b/GUI/Renderer.cpp @@ -23,13 +23,13 @@ namespace NES void Renderer::CleanupDevice() { - if(_pImmediateContext) _pImmediateContext->ClearState(); + if(_pDeviceContext) _pDeviceContext->ClearState(); if(_pRenderTargetView) _pRenderTargetView->Release(); if(_samplerState) _samplerState->Release(); if(_pSwapChain) _pSwapChain->Release(); - if(_pImmediateContext1) _pImmediateContext1->Release(); + if(_pDeviceContext1) _pDeviceContext1->Release(); if(_pd3dDevice1) _pd3dDevice1->Release(); if(_pd3dDevice) _pd3dDevice->Release(); } @@ -85,12 +85,12 @@ namespace NES for(UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) { _driverType = driverTypes[driverTypeIndex]; hr = D3D11CreateDeviceAndSwapChain(nullptr, _driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, - D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &_featureLevel, &_pImmediateContext); + D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &_featureLevel, &_pDeviceContext); if(hr == E_INVALIDARG) { // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it hr = D3D11CreateDeviceAndSwapChain(nullptr, _driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, - D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &_featureLevel, &_pImmediateContext); + D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &_featureLevel, &_pDeviceContext); } if(SUCCEEDED(hr)) { @@ -104,7 +104,7 @@ namespace NES // Obtain the Direct3D 11.1 versions if available hr = _pd3dDevice->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&_pd3dDevice1)); if(SUCCEEDED(hr)) { - (void)_pImmediateContext->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&_pImmediateContext1)); + (void)_pDeviceContext->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&_pDeviceContext1)); } // Create a render target view @@ -120,7 +120,7 @@ namespace NES return hr; } - _pImmediateContext->OMSetRenderTargets(1, &_pRenderTargetView, nullptr); + _pDeviceContext->OMSetRenderTargets(1, &_pRenderTargetView, nullptr); // Setup the viewport UINT fred; @@ -131,7 +131,7 @@ namespace NES vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; - _pImmediateContext->RSSetViewports(1, &vp); + _pDeviceContext->RSSetViewports(1, &vp); _pd3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_B8G8R8A8_UNORM, 16, &fred); @@ -193,8 +193,7 @@ namespace NES } //////////////////////////////////////////////////////////////////////////// - _sprites.reset(new SpriteBatch(_pImmediateContext)); - _overlaySpriteBatch.reset(new SpriteBatch(_pImmediateContext)); + _spriteBatch.reset(new SpriteBatch(_pDeviceContext)); _font.reset(new SpriteFont(_pd3dDevice, L"Calibri.30.spritefont")); @@ -217,8 +216,34 @@ namespace NES return S_OK; } - ID3D11ShaderResourceView* Renderer::GetDisplayBufferShaderResourceView() + ID3D11ShaderResourceView* Renderer::GetShaderResourceView(ID3D11Texture2D* texture) { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + D3D11_TEXTURE2D_DESC desc; + D3D11_RESOURCE_DIMENSION type; + texture->GetType(&type); + texture->GetDesc(&desc); + srvDesc.Format = desc.Format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = desc.MipLevels; + srvDesc.Texture2D.MostDetailedMip = desc.MipLevels - 1; + + ID3D11ShaderResourceView *shaderResourceView = nullptr; + _pd3dDevice->CreateShaderResourceView(texture, &srvDesc, &shaderResourceView); + + return shaderResourceView; + } + + void Renderer::DrawNESScreen() + { + RECT sourceRect; + sourceRect.left = 0; + sourceRect.right = 256; + sourceRect.bottom = 240; + sourceRect.top = 0; + + XMVECTOR position{ { 0, 0 } }; + UINT screenwidth = 256, screenheight = 240; D3D11_MAPPED_SUBRESOURCE dd; @@ -226,25 +251,43 @@ namespace NES dd.RowPitch = screenwidth * 4; dd.DepthPitch = screenwidth* screenheight * 4; - _pImmediateContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd); + _pDeviceContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd); memcpy(dd.pData, _nextFrameBuffer, screenwidth*screenheight * 4); - _pImmediateContext->Unmap(_pTexture, 0); + _pDeviceContext->Unmap(_pTexture, 0); - /////////////////////////////////////////////////////////////////////////////// - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - D3D11_TEXTURE2D_DESC desc; - D3D11_RESOURCE_DIMENSION type; - _pTexture->GetType(&type); - _pTexture->GetDesc(&desc); - srvDesc.Format = desc.Format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = desc.MipLevels; - srvDesc.Texture2D.MostDetailedMip = desc.MipLevels - 1; + ID3D11ShaderResourceView *nesOutputBuffer = GetShaderResourceView(_pTexture); + _spriteBatch->Draw(nesOutputBuffer, position, &sourceRect, Colors::White, 0.0f, position, 4.0f); + nesOutputBuffer->Release(); + } - ID3D11ShaderResourceView *pSRView = nullptr; - _pd3dDevice->CreateShaderResourceView(_pTexture, &srvDesc, &pSRView); + void Renderer::DrawPauseScreen() + { + RECT destRect; + destRect.left = 0; + destRect.right = 256*4; + destRect.bottom = 240*4; + destRect.top = 0; + + XMVECTOR position{ { 0, 0 } }; + + UINT screenwidth = 256*4, screenheight = 240*4; + + D3D11_MAPPED_SUBRESOURCE dd; + dd.pData = (void *)_overlayBuffer; + dd.RowPitch = screenwidth * 4; + dd.DepthPitch = screenwidth* screenheight * 4; + + _pDeviceContext->Map(_overlayTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd); + std::fill_n((uint32_t*)dd.pData, screenwidth*screenheight, 0x99222222); + _pDeviceContext->Unmap(_overlayTexture, 0); + + ID3D11ShaderResourceView *shaderResourceView = GetShaderResourceView(_overlayTexture); + _spriteBatch->Draw(shaderResourceView, destRect); // , position, &sourceRect, Colors::White, 0.0f, position, 4.0f); + shaderResourceView->Release(); + + _font->DrawString(_spriteBatch.get(), L"PAUSED", XMFLOAT2(256 * 2 - 142, 240 * 2 - 37), Colors::Black, 0.0f, XMFLOAT2(0, 0), 2.0f); + _font->DrawString(_spriteBatch.get(), L"PAUSED", XMFLOAT2(256 * 2 - 145, 240 * 2 - 40), Colors::AntiqueWhite, 0.0f, XMFLOAT2(0, 0), 2.0f); - return pSRView; } //-------------------------------------------------------------------------------------- @@ -253,27 +296,24 @@ namespace NES void Renderer::Render() { // Clear the back buffer - _pImmediateContext->ClearRenderTargetView(_pRenderTargetView, Colors::Black); + _pDeviceContext->ClearRenderTargetView(_pRenderTargetView, Colors::Black); - ID3D11ShaderResourceView *shaderResourceView = GetDisplayBufferShaderResourceView(); + _spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, _samplerState); - RECT sourceRect; - sourceRect.left = 0; - sourceRect.right = 256; - sourceRect.bottom = 240; - sourceRect.top = 0; + //Draw nes screen + DrawNESScreen(); - XMVECTOR position{ { 0, 0 } }; - - _overlaySpriteBatch->Begin(SpriteSortMode_Deferred, nullptr, _samplerState); - _overlaySpriteBatch->Draw(shaderResourceView, position, &sourceRect, Colors::White, 0.0f, position, 4.0f); + //Draw FPS counter + if(CheckFlag(UIFlags::ShowFPS)) { + _font->DrawString(_spriteBatch.get(), (wstring(L"FPS: ") + std::to_wstring(Console::GetFPS())).c_str(), XMFLOAT2(256 * 4 - 150, 11), Colors::Yellow, 0.0f, XMFLOAT2(0, 0), 1.0f); + } - _font->DrawString(_overlaySpriteBatch.get(), (wstring(L"FPS: ") + std::to_wstring(Console::GetFPS())).c_str(), XMFLOAT2(256*4-150,11), Colors::Yellow, 0.0f, XMFLOAT2(0,0), 1.0f); + if(CheckFlag(UIFlags::ShowPauseScreen)) { + DrawPauseScreen(); + } - _overlaySpriteBatch->End(); + _spriteBatch->End(); - shaderResourceView->Release(); - // Present the information rendered to the back buffer to the front buffer (the screen) _pSwapChain->Present(0, 0); } diff --git a/GUI/Renderer.h b/GUI/Renderer.h index d930e197..bfd78ed1 100644 --- a/GUI/Renderer.h +++ b/GUI/Renderer.h @@ -6,6 +6,12 @@ using namespace DirectX; namespace NES { + enum UIFlags + { + ShowFPS = 1, + ShowPauseScreen = 2, + }; + class Renderer : IVideoDevice { private: @@ -15,8 +21,8 @@ namespace NES { D3D_FEATURE_LEVEL _featureLevel = D3D_FEATURE_LEVEL_11_0; ID3D11Device* _pd3dDevice = nullptr; ID3D11Device1* _pd3dDevice1 = nullptr; - ID3D11DeviceContext* _pImmediateContext = nullptr; - ID3D11DeviceContext1* _pImmediateContext1 = nullptr; + ID3D11DeviceContext* _pDeviceContext = nullptr; + ID3D11DeviceContext1* _pDeviceContext1 = nullptr; IDXGISwapChain* _pSwapChain = nullptr; ID3D11RenderTargetView* _pRenderTargetView = nullptr; @@ -29,19 +35,37 @@ namespace NES { unique_ptr _font; ID3D11Texture2D* _overlayTexture = nullptr; byte* _overlayBuffer; - std::unique_ptr _overlaySpriteBatch; + std::unique_ptr _spriteBatch; - std::unique_ptr _sprites; + uint32_t _flags = 0; HRESULT InitDevice(); void CleanupDevice(); - ID3D11ShaderResourceView* GetDisplayBufferShaderResourceView(); + + ID3D11ShaderResourceView* GetShaderResourceView(ID3D11Texture2D* texture); + void DrawNESScreen(); + void DrawPauseScreen(); public: Renderer(HWND hWnd); ~Renderer(); void Render(); + + void SetFlags(uint32_t flags) + { + _flags |= flags; + } + + void ClearFlags(uint32_t flags) + { + _flags &= ~flags; + } + + bool CheckFlag(uint32_t flag) + { + return (_flags & flag) == flag; + } void UpdateFrame(uint8_t* frameBuffer) { diff --git a/GUI/resource.h b/GUI/resource.h index b842d368..a26bdc7d 100644 Binary files a/GUI/resource.h and b/GUI/resource.h differ