From c19210b641679be2ab840a6752e06a7539d3ce28 Mon Sep 17 00:00:00 2001 From: "XTra.KrazzY" Date: Fri, 27 Feb 2009 03:56:34 +0000 Subject: [PATCH] Working screenshots for everyone! This may not be the 'best' way to implement it but it's the most compatible, working and least mutually exclusive as possible (works with DC too). More coming soon. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2449 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/Core.cpp | 25 +----- Source/Core/Core/Src/Core.h | 2 - Source/Core/DolphinWX/Src/Frame.cpp | 1 + Source/Core/DolphinWX/Src/Frame.h | 2 + Source/Core/DolphinWX/Src/FrameTools.cpp | 28 +++++- Source/Core/DolphinWX/Src/Globals.h | 1 + Source/PluginSpecs/pluginspecs_video.h | 2 +- Source/Plugins/Plugin_VideoDX9/Src/main.cpp | 7 +- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 90 +++++++++++++++---- Source/Plugins/Plugin_VideoOGL/Src/Render.h | 3 +- Source/Plugins/Plugin_VideoOGL/Src/main.cpp | 20 +---- 11 files changed, 110 insertions(+), 71 deletions(-) diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index d08d78fe59..e051a07eb1 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -649,12 +649,8 @@ EState GetState() } return CORE_UNINITIALIZED; } -/////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////////// // Save or recreate the emulation state -// ---------- void SaveState() { State_Save(0); } @@ -662,28 +658,9 @@ void SaveState() { void LoadState() { State_Load(0); } -/////////////////////////////////////// + - -bool MakeScreenshot(const std::string &filename) -{ - - bool bResult = false; - CPluginManager &pManager = CPluginManager::GetInstance(); - - if (pManager.GetVideo()->IsValid()) - { - TCHAR szTmpFilename[MAX_PATH]; - strcpy(szTmpFilename, filename.c_str()); - bResult = pManager.GetVideo()->Video_Screenshot(szTmpFilename) ? true : false; - } - return bResult; -} - - -///////////////////////////////////////////////////////////////////////////////////////////////////// // --- Callbacks for plugins / engine --- -///////////////////////////////////////////////////////////////////////////////////////////////////// // __________________________________________________________________________________________________ // Callback_VideoLog diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h index 4d77746815..6f9bae13c0 100644 --- a/Source/Core/Core/Src/Core.h +++ b/Source/Core/Core/Src/Core.h @@ -55,8 +55,6 @@ namespace Core const SCoreStartupParameter& GetStartupParameter(); extern SCoreStartupParameter g_CoreStartupParameter; - // Make a screen shot - bool MakeScreenshot(const std::string& _rFilename); void* GetWindowHandle(); bool GetRealWiimote(); void ReconnectWiimote(); diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index 74087a9037..27bad78760 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -248,6 +248,7 @@ EVT_MENU(IDM_HELPABOUT, CFrame::OnHelp) EVT_MENU(wxID_REFRESH, CFrame::OnRefresh) EVT_MENU(IDM_PLAY, CFrame::OnPlay) EVT_MENU(IDM_STOP, CFrame::OnStop) +EVT_MENU(IDM_SCREENSHOT, CFrame::OnScreenshot) EVT_MENU(IDM_CONFIG_MAIN, CFrame::OnConfigMain) EVT_MENU(IDM_CONFIG_GFX_PLUGIN, CFrame::OnPluginGFX) EVT_MENU(IDM_CONFIG_DSP_PLUGIN, CFrame::OnPluginDSP) diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 14cb29c41f..36af0d5b2d 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -125,6 +125,7 @@ class CFrame : public wxFrame Toolbar_Play, Toolbar_Stop, Toolbar_Pause, + Toolbar_Screenshot, Toolbar_FullScreen, Toolbar_PluginOptions, Toolbar_PluginGFX, @@ -180,6 +181,7 @@ class CFrame : public wxFrame void OnPlay(wxCommandEvent& event); // Emulation void OnChangeDisc(wxCommandEvent& event); void OnStop(wxCommandEvent& event); + void OnScreenshot(wxCommandEvent& event); void OnClose(wxCloseEvent &event); void OnLoadState(wxCommandEvent& event); void OnSaveState(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 18190ac1ea..39b4879425 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -195,6 +195,7 @@ void CFrame::PopulateToolbar(wxToolBar* toolBar) #ifdef _WIN32 toolBar->AddTool(IDM_TOGGLE_FULLSCREEN, _T("Fullscr."), m_Bitmaps[Toolbar_FullScreen], _T("Toggle Fullscreen")); #endif + toolBar->AddTool(IDM_SCREENSHOT, _T("Screenshot"), m_Bitmaps[Toolbar_FullScreen], _T("Screenshot")); toolBar->AddSeparator(); toolBar->AddTool(IDM_CONFIG_MAIN, _T("Config"), m_Bitmaps[Toolbar_PluginOptions], _T("Configure...")); toolBar->AddTool(IDM_CONFIG_GFX_PLUGIN, _T("Gfx"), m_Bitmaps[Toolbar_PluginGFX], _T("Graphics settings")); @@ -512,12 +513,32 @@ void CFrame::OnBrowse(wxCommandEvent& WXUNUSED (event)) { m_GameListCtrl->BrowseForDirectory(); } -//////////////////////////////////////////////////// + +static inline void GenerateScreenshotName(std::string& name) +{ + int index = 1; + std::string tempname; + tempname = FULL_SCREENSHOTS_DIR; + tempname += Core::GetStartupParameter().GetUniqueID(); + + name = StringFromFormat("%s-%d.bmp", tempname.c_str(), index); + + while(File::Exists(name.c_str())) + name = StringFromFormat("%s-%d.bmp", tempname.c_str(), ++index); +} + +void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED (event)) +{ + std::string name; + GenerateScreenshotName(name); + + Core::SetState(Core::CORE_PAUSE); + CPluginManager::GetInstance().GetVideo()->Video_Screenshot(name.c_str()); + Core::SetState(Core::CORE_RUN); +} -////////////////////////////////////////////////////////////////////////////////////// // Stop the emulation -// ------------- void CFrame::DoStop() { // Music modification @@ -741,6 +762,7 @@ void CFrame::UpdateGUI() GetToolBar()->EnableTool(wxID_OPEN, !initialized); GetToolBar()->EnableTool(wxID_REFRESH, !initialized); // Don't allow refresh when we don't show the list GetToolBar()->EnableTool(IDM_STOP, running || paused); + GetToolBar()->EnableTool(IDM_SCREENSHOT, running || paused); } // File diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index 24cfa88c96..b55503a626 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -52,6 +52,7 @@ enum IDM_LOADSLOT10, IDM_PLAY, IDM_STOP, + IDM_SCREENSHOT, IDM_BROWSE, IDM_DRIVE1, IDM_DRIVE24 = IDM_DRIVE1 + 23,//248, diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index bf6d191a70..66edbd2005 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -113,7 +113,7 @@ EXPORT void CALL Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dw // input: Filename // output: TRUE if all was okay // -EXPORT unsigned int CALL Video_Screenshot(TCHAR* _szFilename); +EXPORT void CALL Video_Screenshot(const char *_szFilename); // __________________________________________________________________________________________________ // Function: Video_EnterLoop diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index 601926afef..d2d4dddac1 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -283,7 +283,7 @@ void __Log(int log, const char *format, ...) } -HRESULT ScreenShot(TCHAR *File) +HRESULT ScreenShot(const char *File) { if (D3D::dev == NULL) return S_FALSE; @@ -314,7 +314,8 @@ HRESULT ScreenShot(TCHAR *File) return S_OK; } -unsigned int Video_Screenshot(TCHAR* _szFilename) +void Video_Screenshot(const char *_szFilename) { - return ScreenShot(_szFilename) == S_OK ? TRUE : FALSE; + if(ScreenShot(_szFilename) != S_OK) + PanicAlert("Error while capturing screen"); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index c396427c02..0a72e46dd9 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -52,6 +52,10 @@ #include "OS/Win32.h" #endif +#if defined(HAVE_WX) && HAVE_WX +#include +#endif + #ifdef _WIN32 #include "Win32Window.h" // warning: crapcode #else @@ -79,6 +83,10 @@ static GLuint s_ZBufferTarget = 0; static bool s_bATIDrawBuffers = false; static bool s_bHaveStencilBuffer = false; +static bool s_bScreenshot = false; +static Common::CriticalSection s_criticalScreenshot; +static std::string s_sScreenshotName; + static Renderer::RenderMode s_RenderMode = Renderer::RM_Normal; bool g_bBlendSeparate = false; int frameCount; @@ -1065,6 +1073,21 @@ void Renderer::Swap(const TRectangle& rc) } // ------------------------------------- + // Take screenshot, if necessary + if(s_bScreenshot) { + s_criticalScreenshot.Enter(); + + if(SaveRenderTarget(s_sScreenshotName.c_str())) { + char msg[255]; + sprintf(msg, "Saved %s\n", s_sScreenshotName.c_str()); + OSD::AddMessage(msg, 500); + } else + PanicAlert("Error while capturing screen"); + + s_sScreenshotName = ""; + s_bScreenshot = false; + s_criticalScreenshot.Leave(); + } // Place messages on the picture, then copy it to the screen SwapBuffers(); @@ -1240,28 +1263,57 @@ void Renderer::RenderText(const char* pstr, int left, int top, u32 color) 0, nBackbufferWidth, nBackbufferHeight); } -bool Renderer::SaveRenderTarget(const char* filename, int jpeg) +void Renderer::SetScreenshot(const char *filename) { - bool bflip = true; - int nBackbufferHeight = (int)OpenGL_GetHeight(); - int nBackbufferWidth = (int)OpenGL_GetWidth(); + s_criticalScreenshot.Enter(); + s_sScreenshotName = filename; + s_bScreenshot = true; - std::vector data(nBackbufferWidth * nBackbufferHeight); - glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]); - if (glGetError() != GL_NO_ERROR) - return false; + s_criticalScreenshot.Leave(); +} - if (bflip) { - // swap scanlines - std::vector scanline(nBackbufferWidth); - for (int i = 0; i < nBackbufferHeight/2; ++i) { - memcpy(&scanline[0], &data[i*nBackbufferWidth], nBackbufferWidth*4); - memcpy(&data[i*nBackbufferWidth], &data[(nBackbufferHeight-i-1)*nBackbufferWidth], nBackbufferWidth*4); - memcpy(&data[(nBackbufferHeight-i-1)*nBackbufferWidth], &scanline[0], nBackbufferWidth*4); - } - } - - return SaveTGA(filename, nBackbufferWidth, nBackbufferHeight, &data[0]); +bool Renderer::SaveRenderTarget(const char *filename) +{ + int w = (int)OpenGL_GetWidth(), h = (int)OpenGL_GetHeight(); + bool result = false; + + if(!filename) + return false; + + u8 *data = (u8 *)malloc(3 * w * h); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, data); + + if (glGetError() != GL_NO_ERROR) + return false; + + // Flip image + for(int y = 0; y < h / 2; y++) { + for(int x = 0; x < w; x++) { + std::swap(data[(y * w + x) * 3], + data[((h - 1 - y) * w + x) * 3]); + + std::swap(data[(y * w + x) * 3 + 1], + data[((h - 1 - y) * w + x) * 3 + 1]); + + std::swap(data[(y * w + x) * 3 + 2], + data[((h - 1 - y) * w + x) * 3 + 2]); + } + } + +#if defined(HAVE_WX) && HAVE_WX + wxImage a(w, h, data); + + a.SaveFile(wxString::FromAscii(filename), wxBITMAP_TYPE_BMP); + result = true; +#else + result = SaveTGA(filename, w, h, data); + + free(data); +#endif + + return result; } ////////////////////////////////////////////////////////////////////////////////////// diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.h b/Source/Plugins/Plugin_VideoOGL/Src/Render.h index 83685b48eb..4915c141a7 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.h @@ -126,7 +126,8 @@ public: // Random utilities static void RenderText(const char* pstr, int left, int top, u32 color); - static bool SaveRenderTarget(const char* filename, int jpeg); + static void SetScreenshot(const char *filename); + static bool SaveRenderTarget(const char *filename); // Finish up the current frame, print some stats static void Swap(const TRectangle& rc); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index 74c1763182..5b3be7b2b1 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -337,25 +337,9 @@ void DebugLog(const char* _fmt, ...) #endif } -unsigned int Video_Screenshot(TCHAR* _szFilename) +void Video_Screenshot(const char *_szFilename) { - char str[64]; - int left = 200, top = 15; - sprintf(str, "Dolphin OpenGL"); - - Renderer::ResetGLState(); - Renderer::RenderText(str, left+1, top+1, 0xff000000); - Renderer::RenderText(str, left, top, 0xffc0ffff); - Renderer::RestoreGLState(); - - if (Renderer::SaveRenderTarget(_szFilename, 0)) - { - char msg[255]; - sprintf(msg, "saved %s\n", _szFilename); - OSD::AddMessage(msg, 500); - return true; - } - return false; + Renderer::SetScreenshot(_szFilename); } void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling)