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)