From 259f474ec7ad7da7b0ab3951ef32b12d5ddcbfc2 Mon Sep 17 00:00:00 2001 From: Souryo Date: Thu, 10 Jul 2014 21:17:37 -0400 Subject: [PATCH] Support for saving PNG screenshots --- .gitignore | 1 + GUI/GUI.rc | Bin 22248 -> 22522 bytes GUI/MainWindow.cpp | 10 ++++-- GUI/Renderer.cpp | 46 ++++++++++++++++++++++++++++ GUI/Renderer.h | 12 +++++--- GUI/resource.h | Bin 7294 -> 7388 bytes Utilities/FolderUtilities.cpp | 7 +++++ Utilities/FolderUtilities.h | 1 + Utilities/PNGWriter.h | 25 +++++++++++++++ Utilities/Utilities.vcxproj | 1 + Utilities/Utilities.vcxproj.filters | 3 ++ 11 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 Utilities/PNGWriter.h diff --git a/.gitignore b/.gitignore index 25396395..31b1d791 100644 --- a/.gitignore +++ b/.gitignore @@ -159,3 +159,4 @@ $RECYCLE.BIN/ *.svs *.spritefont *.trt +*.zip diff --git a/GUI/GUI.rc b/GUI/GUI.rc index 6b8a3e27bfcfb8468b41bcb15aaefe8205494c7b..a1759c988c0b0e6ff45754dd2c3309da05f12b82 100644 GIT binary patch delta 203 zcmaE{mhsnm#tn<)CMSrXGc?`u284URhB@8h@?8aco zU^F>UR&??KWj3ICe<1V$s*Yy}VQ^&dW^e_vof(3Fv@3%jknI7K51Bk)Tz~Tsxd7(L zX6g-_#grznY~H3mk7@D(RgTF^)Mhb*j4b2^8>vc^k(1x6NlxZd6`9QDdth>cmC|N2 H?M>PM_F^(b delta 41 zcmV+^0M`HduL0<-0kEPTldKmavsNEa1G6L}k_3}pDwvb5B6zd5C!PYcW-F8|b diff --git a/GUI/MainWindow.cpp b/GUI/MainWindow.cpp index 3f146ef3..b183ef45 100644 --- a/GUI/MainWindow.cpp +++ b/GUI/MainWindow.cpp @@ -359,6 +359,8 @@ namespace NES SetMenuEnabled(ID_NETPLAY_CONNECT, !serverStarted && !clientConnected && !Movie::Playing()); SetMenuEnabled(ID_NETPLAY_DISCONNECT, !serverStarted && clientConnected); + SetMenuEnabled(ID_TOOLS_TAKESCREENSHOT, running); + SetMenuCheck(ID_SAVESTATESLOT_1, _currentSaveSlot == 0); SetMenuCheck(ID_SAVESTATESLOT_2, _currentSaveSlot == 1); SetMenuCheck(ID_SAVESTATESLOT_3, _currentSaveSlot == 2); @@ -374,8 +376,8 @@ namespace NES } _currentROM = _console->GetROMPath(); - wstring currentROMName = FolderUtilities::GetFilename(_console->GetROMPath(), false); - SetWindowText(_hWnd, (wstring(_windowName) + L": " + currentROMName).c_str()); + _currentROMName = FolderUtilities::GetFilename(_console->GetROMPath(), false); + SetWindowText(_hWnd, (wstring(_windowName) + L": " + _currentROMName).c_str()); Console::ClearFlags(EmulationFlags::Paused); @@ -642,6 +644,10 @@ namespace NES GameClient::Disconnect(); break; + case ID_TOOLS_TAKESCREENSHOT: + mainWindow->_renderer->TakeScreenshot(mainWindow->_currentROMName); + break; + case ID_TESTS_RUNTESTS: mainWindow->RunTests(); break; diff --git a/GUI/Renderer.cpp b/GUI/Renderer.cpp index 1af5c959..5cd8b3fa 100644 --- a/GUI/Renderer.cpp +++ b/GUI/Renderer.cpp @@ -329,7 +329,9 @@ namespace NES dd.DepthPitch = _screenBufferSize; _pDeviceContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd); + _frameLock.Acquire(); memcpy(dd.pData, _nextFrameBuffer, _screenBufferSize); + _frameLock.Release(); _pDeviceContext->Unmap(_pTexture, 0); ID3D11ShaderResourceView *nesOutputBuffer = GetShaderResourceView(_pTexture); @@ -407,4 +409,48 @@ namespace NES _pSwapChain->Present(0, 0); } } + + void Renderer::UpdateFrame(uint8_t* frameBuffer) + { + _frameChanged = true; + + _frameLock.Acquire(); + memcpy(_nextFrameBuffer, frameBuffer, 256 * 240 * 4); + _frameLock.Release(); + } + + void Renderer::TakeScreenshot(wstring romFilename) + { + uint32_t* frameBuffer = new uint32_t[256 * 240]; + + _frameLock.Acquire(); + memcpy(frameBuffer, _nextFrameBuffer, 256 * 240 * 4); + _frameLock.Release(); + + //ARGB -> ABGR + for(uint32_t i = 0; i < 256 * 240; i++) { + frameBuffer[i] = (frameBuffer[i] & 0xFF00FF00) | ((frameBuffer[i] & 0xFF0000) >> 16) | ((frameBuffer[i] & 0xFF) << 16); + } + + int counter = 0; + wstring baseFilename = FolderUtilities::GetScreenshotFolder() + romFilename; + wstring ssFilename; + while(true) { + wstring counterStr = std::to_wstring(counter); + while(counterStr.length() < 3) { + counterStr = L"0" + counterStr; + } + ssFilename = baseFilename + L"_" + counterStr + L".png"; + ifstream file(ssFilename, ios::in); + if(file) { + file.close(); + } else { + break; + } + counter++; + } + + PNGWriter::WritePNG(ssFilename, (uint8_t*)frameBuffer, 256, 240); + } + } \ No newline at end of file diff --git a/GUI/Renderer.h b/GUI/Renderer.h index b77cc79d..95b8cea6 100644 --- a/GUI/Renderer.h +++ b/GUI/Renderer.h @@ -3,6 +3,9 @@ #include "DirectXTK\SpriteFont.h" #include "../Core/IVideoDevice.h" #include "../Core/IMessageManager.h" +#include "../Utilities/PNGWriter.h" +#include "../Utilities/FolderUtilities.h" +#include "../Utilities/SimpleLock.h" using namespace DirectX; @@ -33,6 +36,8 @@ namespace NES { bool _frameChanged = true; uint8_t* _nextFrameBuffer = nullptr; + SimpleLock _frameLock; + unique_ptr _font; ID3D11Texture2D* _overlayTexture = nullptr; @@ -91,10 +96,7 @@ namespace NES { return (_flags & flag) == flag; } - void UpdateFrame(uint8_t* frameBuffer) - { - _frameChanged = true; - memcpy(_nextFrameBuffer, frameBuffer, 256 * 240 * 4); - } + void UpdateFrame(uint8_t* frameBuffer); + void TakeScreenshot(wstring romFilename); }; } \ No newline at end of file diff --git a/GUI/resource.h b/GUI/resource.h index 35981c4d45ff17755883389b2a524f8b68ad4831..e2a8fb7f1a017404f7175c5fb87fc3c319c7e421 100644 GIT binary patch delta 64 zcmexoamR8)gXH90B7Bk|42}%m46Y2p49*NeK-!hT56Jdl@SpsUOLUSX$K)VEsm%?N SN=%b4F^Nr*7MXlTdJ_OhOA;Ia delta 28 kcmca(`OjiQgXH7|%q*K9Ny;%zJ|ZbLIZj$+vX;yy0It;v&Hw-a diff --git a/Utilities/FolderUtilities.cpp b/Utilities/FolderUtilities.cpp index 8d4e3257..440bb6df 100644 --- a/Utilities/FolderUtilities.cpp +++ b/Utilities/FolderUtilities.cpp @@ -39,6 +39,13 @@ wstring FolderUtilities::GetMovieFolder() return folder; } +wstring FolderUtilities::GetScreenshotFolder() +{ + wstring folder = GetHomeFolder() + L"Screenshots\\"; + CreateDirectory(folder.c_str(), nullptr); + return folder; +} + vector FolderUtilities::GetFolders(wstring rootFolder) { HANDLE hFind; diff --git a/Utilities/FolderUtilities.h b/Utilities/FolderUtilities.h index 60a182b7..805d2d03 100644 --- a/Utilities/FolderUtilities.h +++ b/Utilities/FolderUtilities.h @@ -9,6 +9,7 @@ class FolderUtilities static wstring GetSaveFolder(); static wstring GetSaveStateFolder(); static wstring GetMovieFolder(); + static wstring GetScreenshotFolder(); static vector GetFolders(wstring rootFolder); static vector GetFilesInFolder(wstring rootFolder, wstring mask, bool recursive); diff --git a/Utilities/PNGWriter.h b/Utilities/PNGWriter.h new file mode 100644 index 00000000..4aaf0619 --- /dev/null +++ b/Utilities/PNGWriter.h @@ -0,0 +1,25 @@ +#pragma once +#include "stdafx.h" +#include "miniz.h" +using std::ofstream; + +class PNGWriter +{ +public: + static bool WritePNG(wstring filename, uint8_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32) + { + size_t pngSize = 0; + void *pngData = tdefl_write_image_to_png_file_in_memory_ex(buffer, xSize, ySize, bitsPerPixel/8, &pngSize, MZ_DEFAULT_LEVEL, MZ_FALSE); + if(!pngData) { + std::cout << "tdefl_write_image_to_png_file_in_memory_ex() failed!" << std::endl; + return false; + } else { + ofstream file(filename, ios::out | ios::binary); + file.write((char*)pngData, pngSize); + file.close(); + mz_free(pngData); + return true; + } + } + +}; \ No newline at end of file diff --git a/Utilities/Utilities.vcxproj b/Utilities/Utilities.vcxproj index bd18cd40..c30d5d88 100644 --- a/Utilities/Utilities.vcxproj +++ b/Utilities/Utilities.vcxproj @@ -75,6 +75,7 @@ + diff --git a/Utilities/Utilities.vcxproj.filters b/Utilities/Utilities.vcxproj.filters index c7648318..213fbbf5 100644 --- a/Utilities/Utilities.vcxproj.filters +++ b/Utilities/Utilities.vcxproj.filters @@ -56,6 +56,9 @@ Header Files + + Header Files +