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
This commit is contained in:
parent
8f303fb63e
commit
c19210b641
|
@ -649,12 +649,8 @@ EState GetState()
|
||||||
}
|
}
|
||||||
return CORE_UNINITIALIZED;
|
return CORE_UNINITIALIZED;
|
||||||
}
|
}
|
||||||
///////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Save or recreate the emulation state
|
// Save or recreate the emulation state
|
||||||
// ----------
|
|
||||||
void SaveState() {
|
void SaveState() {
|
||||||
State_Save(0);
|
State_Save(0);
|
||||||
}
|
}
|
||||||
|
@ -662,28 +658,9 @@ void SaveState() {
|
||||||
void LoadState() {
|
void LoadState() {
|
||||||
State_Load(0);
|
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 ---
|
// --- Callbacks for plugins / engine ---
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// Callback_VideoLog
|
// Callback_VideoLog
|
||||||
|
|
|
@ -55,8 +55,6 @@ namespace Core
|
||||||
const SCoreStartupParameter& GetStartupParameter();
|
const SCoreStartupParameter& GetStartupParameter();
|
||||||
extern SCoreStartupParameter g_CoreStartupParameter;
|
extern SCoreStartupParameter g_CoreStartupParameter;
|
||||||
|
|
||||||
// Make a screen shot
|
|
||||||
bool MakeScreenshot(const std::string& _rFilename);
|
|
||||||
void* GetWindowHandle();
|
void* GetWindowHandle();
|
||||||
bool GetRealWiimote();
|
bool GetRealWiimote();
|
||||||
void ReconnectWiimote();
|
void ReconnectWiimote();
|
||||||
|
|
|
@ -248,6 +248,7 @@ EVT_MENU(IDM_HELPABOUT, CFrame::OnHelp)
|
||||||
EVT_MENU(wxID_REFRESH, CFrame::OnRefresh)
|
EVT_MENU(wxID_REFRESH, CFrame::OnRefresh)
|
||||||
EVT_MENU(IDM_PLAY, CFrame::OnPlay)
|
EVT_MENU(IDM_PLAY, CFrame::OnPlay)
|
||||||
EVT_MENU(IDM_STOP, CFrame::OnStop)
|
EVT_MENU(IDM_STOP, CFrame::OnStop)
|
||||||
|
EVT_MENU(IDM_SCREENSHOT, CFrame::OnScreenshot)
|
||||||
EVT_MENU(IDM_CONFIG_MAIN, CFrame::OnConfigMain)
|
EVT_MENU(IDM_CONFIG_MAIN, CFrame::OnConfigMain)
|
||||||
EVT_MENU(IDM_CONFIG_GFX_PLUGIN, CFrame::OnPluginGFX)
|
EVT_MENU(IDM_CONFIG_GFX_PLUGIN, CFrame::OnPluginGFX)
|
||||||
EVT_MENU(IDM_CONFIG_DSP_PLUGIN, CFrame::OnPluginDSP)
|
EVT_MENU(IDM_CONFIG_DSP_PLUGIN, CFrame::OnPluginDSP)
|
||||||
|
|
|
@ -125,6 +125,7 @@ class CFrame : public wxFrame
|
||||||
Toolbar_Play,
|
Toolbar_Play,
|
||||||
Toolbar_Stop,
|
Toolbar_Stop,
|
||||||
Toolbar_Pause,
|
Toolbar_Pause,
|
||||||
|
Toolbar_Screenshot,
|
||||||
Toolbar_FullScreen,
|
Toolbar_FullScreen,
|
||||||
Toolbar_PluginOptions,
|
Toolbar_PluginOptions,
|
||||||
Toolbar_PluginGFX,
|
Toolbar_PluginGFX,
|
||||||
|
@ -180,6 +181,7 @@ class CFrame : public wxFrame
|
||||||
void OnPlay(wxCommandEvent& event); // Emulation
|
void OnPlay(wxCommandEvent& event); // Emulation
|
||||||
void OnChangeDisc(wxCommandEvent& event);
|
void OnChangeDisc(wxCommandEvent& event);
|
||||||
void OnStop(wxCommandEvent& event);
|
void OnStop(wxCommandEvent& event);
|
||||||
|
void OnScreenshot(wxCommandEvent& event);
|
||||||
void OnClose(wxCloseEvent &event);
|
void OnClose(wxCloseEvent &event);
|
||||||
void OnLoadState(wxCommandEvent& event);
|
void OnLoadState(wxCommandEvent& event);
|
||||||
void OnSaveState(wxCommandEvent& event);
|
void OnSaveState(wxCommandEvent& event);
|
||||||
|
|
|
@ -195,6 +195,7 @@ void CFrame::PopulateToolbar(wxToolBar* toolBar)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
toolBar->AddTool(IDM_TOGGLE_FULLSCREEN, _T("Fullscr."), m_Bitmaps[Toolbar_FullScreen], _T("Toggle Fullscreen"));
|
toolBar->AddTool(IDM_TOGGLE_FULLSCREEN, _T("Fullscr."), m_Bitmaps[Toolbar_FullScreen], _T("Toggle Fullscreen"));
|
||||||
#endif
|
#endif
|
||||||
|
toolBar->AddTool(IDM_SCREENSHOT, _T("Screenshot"), m_Bitmaps[Toolbar_FullScreen], _T("Screenshot"));
|
||||||
toolBar->AddSeparator();
|
toolBar->AddSeparator();
|
||||||
toolBar->AddTool(IDM_CONFIG_MAIN, _T("Config"), m_Bitmaps[Toolbar_PluginOptions], _T("Configure..."));
|
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"));
|
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();
|
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
|
// Stop the emulation
|
||||||
// -------------
|
|
||||||
void CFrame::DoStop()
|
void CFrame::DoStop()
|
||||||
{
|
{
|
||||||
// Music modification
|
// Music modification
|
||||||
|
@ -741,6 +762,7 @@ void CFrame::UpdateGUI()
|
||||||
GetToolBar()->EnableTool(wxID_OPEN, !initialized);
|
GetToolBar()->EnableTool(wxID_OPEN, !initialized);
|
||||||
GetToolBar()->EnableTool(wxID_REFRESH, !initialized); // Don't allow refresh when we don't show the list
|
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_STOP, running || paused);
|
||||||
|
GetToolBar()->EnableTool(IDM_SCREENSHOT, running || paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
// File
|
// File
|
||||||
|
|
|
@ -52,6 +52,7 @@ enum
|
||||||
IDM_LOADSLOT10,
|
IDM_LOADSLOT10,
|
||||||
IDM_PLAY,
|
IDM_PLAY,
|
||||||
IDM_STOP,
|
IDM_STOP,
|
||||||
|
IDM_SCREENSHOT,
|
||||||
IDM_BROWSE,
|
IDM_BROWSE,
|
||||||
IDM_DRIVE1,
|
IDM_DRIVE1,
|
||||||
IDM_DRIVE24 = IDM_DRIVE1 + 23,//248,
|
IDM_DRIVE24 = IDM_DRIVE1 + 23,//248,
|
||||||
|
|
|
@ -113,7 +113,7 @@ EXPORT void CALL Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dw
|
||||||
// input: Filename
|
// input: Filename
|
||||||
// output: TRUE if all was okay
|
// 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
|
// Function: Video_EnterLoop
|
||||||
|
|
|
@ -283,7 +283,7 @@ void __Log(int log, const char *format, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT ScreenShot(TCHAR *File)
|
HRESULT ScreenShot(const char *File)
|
||||||
{
|
{
|
||||||
if (D3D::dev == NULL)
|
if (D3D::dev == NULL)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
@ -314,7 +314,8 @@ HRESULT ScreenShot(TCHAR *File)
|
||||||
return S_OK;
|
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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,10 @@
|
||||||
#include "OS/Win32.h"
|
#include "OS/Win32.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_WX) && HAVE_WX
|
||||||
|
#include <wx/image.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Win32Window.h" // warning: crapcode
|
#include "Win32Window.h" // warning: crapcode
|
||||||
#else
|
#else
|
||||||
|
@ -79,6 +83,10 @@ static GLuint s_ZBufferTarget = 0;
|
||||||
static bool s_bATIDrawBuffers = false;
|
static bool s_bATIDrawBuffers = false;
|
||||||
static bool s_bHaveStencilBuffer = 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;
|
static Renderer::RenderMode s_RenderMode = Renderer::RM_Normal;
|
||||||
bool g_bBlendSeparate = false;
|
bool g_bBlendSeparate = false;
|
||||||
int frameCount;
|
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
|
// Place messages on the picture, then copy it to the screen
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
|
@ -1240,28 +1263,57 @@ void Renderer::RenderText(const char* pstr, int left, int top, u32 color)
|
||||||
0, nBackbufferWidth, nBackbufferHeight);
|
0, nBackbufferWidth, nBackbufferHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Renderer::SaveRenderTarget(const char* filename, int jpeg)
|
void Renderer::SetScreenshot(const char *filename)
|
||||||
{
|
{
|
||||||
bool bflip = true;
|
s_criticalScreenshot.Enter();
|
||||||
int nBackbufferHeight = (int)OpenGL_GetHeight();
|
s_sScreenshotName = filename;
|
||||||
int nBackbufferWidth = (int)OpenGL_GetWidth();
|
s_bScreenshot = true;
|
||||||
|
|
||||||
|
s_criticalScreenshot.Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
std::vector<u32> data(nBackbufferWidth * nBackbufferHeight);
|
|
||||||
glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
|
|
||||||
if (glGetError() != GL_NO_ERROR)
|
if (glGetError() != GL_NO_ERROR)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bflip) {
|
// Flip image
|
||||||
// swap scanlines
|
for(int y = 0; y < h / 2; y++) {
|
||||||
std::vector<u32> scanline(nBackbufferWidth);
|
for(int x = 0; x < w; x++) {
|
||||||
for (int i = 0; i < nBackbufferHeight/2; ++i) {
|
std::swap(data[(y * w + x) * 3],
|
||||||
memcpy(&scanline[0], &data[i*nBackbufferWidth], nBackbufferWidth*4);
|
data[((h - 1 - y) * w + x) * 3]);
|
||||||
memcpy(&data[i*nBackbufferWidth], &data[(nBackbufferHeight-i-1)*nBackbufferWidth], nBackbufferWidth*4);
|
|
||||||
memcpy(&data[(nBackbufferHeight-i-1)*nBackbufferWidth], &scanline[0], nBackbufferWidth*4);
|
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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SaveTGA(filename, nBackbufferWidth, nBackbufferHeight, &data[0]);
|
#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -126,7 +126,8 @@ public:
|
||||||
|
|
||||||
// Random utilities
|
// Random utilities
|
||||||
static void RenderText(const char* pstr, int left, int top, u32 color);
|
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
|
// Finish up the current frame, print some stats
|
||||||
static void Swap(const TRectangle& rc);
|
static void Swap(const TRectangle& rc);
|
||||||
|
|
|
@ -337,25 +337,9 @@ void DebugLog(const char* _fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Video_Screenshot(TCHAR* _szFilename)
|
void Video_Screenshot(const char *_szFilename)
|
||||||
{
|
{
|
||||||
char str[64];
|
Renderer::SetScreenshot(_szFilename);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling)
|
void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling)
|
||||||
|
|
Loading…
Reference in New Issue