From df91fc8648114a93d4e1168134570c801713f86b Mon Sep 17 00:00:00 2001 From: hrydgard Date: Tue, 9 Jun 2009 19:40:47 +0000 Subject: [PATCH] Post-processing: Added options to graphics config dialog. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3391 8ced0084-cf51-0410-be5f-012b33b47a6e --- Data/User/Shaders/acidtrip.txt | 6 ++ Source/Core/Common/Src/FileUtil.h | 2 +- .../Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp | 80 +++++++++++++++++++ .../Plugin_VideoOGL/Src/GUI/ConfigDlg.h | 12 ++- .../Plugin_VideoOGL/Src/PixelShaderCache.cpp | 6 +- .../Plugin_VideoOGL/Src/PostProcessing.cpp | 32 ++++---- .../Plugin_VideoOGL/Src/PostProcessing.h | 4 +- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 33 +++++--- 8 files changed, 142 insertions(+), 33 deletions(-) create mode 100644 Data/User/Shaders/acidtrip.txt diff --git a/Data/User/Shaders/acidtrip.txt b/Data/User/Shaders/acidtrip.txt new file mode 100644 index 0000000000..a5abb48d8a --- /dev/null +++ b/Data/User/Shaders/acidtrip.txt @@ -0,0 +1,6 @@ +uniform samplerRECT samp0 : register(s0); + +void main(out float4 ocol0 : COLOR0, in float2 uv0 : TEXCOORD0) +{ + ocol0 = (texRECT(samp0, uv0+1).rgba - texRECT(samp0, uv0-1).rgba)*8; +} diff --git a/Source/Core/Common/Src/FileUtil.h b/Source/Core/Common/Src/FileUtil.h index 0975401786..b528d5a949 100644 --- a/Source/Core/Common/Src/FileUtil.h +++ b/Source/Core/Common/Src/FileUtil.h @@ -67,7 +67,7 @@ bool Copy(const char *srcFilename, const char *destFilename); // creates an empty file filename, returns true on success bool CreateEmptyFile(const char *filename); - + // Scans the directory tree gets, starting from _Directory and adds the // results into parentEntry. Returns the number of files+directories found u32 ScanDirectoryTree(const char *directory, FSTEntry& parentEntry); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp index 84d26c94f9..db698313e0 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp @@ -15,13 +15,21 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#include +#include +#include +#include +#include +#include #include "ConfigDlg.h" +#include "FileUtil.h" #include "../Globals.h" #include "../Config.h" #include "../TextureMngr.h" #include "VertexShaderManager.h" +#include "PostProcessing.h" BEGIN_EVENT_TABLE(ConfigDialog,wxDialog) EVT_CLOSE(ConfigDialog::OnClose) @@ -70,6 +78,9 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog) EVT_RADIOBUTTON(ID_RADIO_COPYEFBTORAM, ConfigDialog::AdvancedSettingsChanged) EVT_RADIOBUTTON(ID_RADIO_COPYEFBTOGL, ConfigDialog::AdvancedSettingsChanged) EVT_CHOICE(ID_PHACKVALUE, ConfigDialog::GeneralSettingsChanged) + EVT_CHOICE(ID_POSTSHADER, ConfigDialog::GeneralSettingsChanged) + EVT_BUTTON(ID_RELOADSHADER, ConfigDialog::ReloadShaderClick) + EVT_BUTTON(ID_EDITSHADER, ConfigDialog::EditShaderClick) END_EVENT_TABLE() ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style) @@ -260,6 +271,34 @@ void ConfigDialog::CreateGUIControls() m_ForceFiltering = new wxCheckBox(m_PageGeneral, ID_FORCEFILTERING, wxT("Force bi/trilinear filtering"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_ForceFiltering->SetValue(g_Config.bForceFiltering); + wxStaticText *PostShaderText = new wxStaticText(m_PageGeneral, ID_POSTSHADERTEXT, wxT("Post-processing shader:"), wxDefaultPosition, wxDefaultSize, 0); + m_PostShaderCB = new wxChoice(m_PageGeneral, ID_POSTSHADER, wxDefaultPosition, wxDefaultSize, arrayStringFor_PostShaderCB, 0, wxDefaultValidator); + m_PostShaderCB->Append(wxT("(off)")); + m_ReloadShader = new wxButton(m_PageGeneral, ID_RELOADSHADER, wxT("&Reload"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_EditShader = new wxButton(m_PageGeneral, ID_EDITSHADER, wxT("&Edit"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + + if (File::IsDirectory("User/Shaders")) + { + File::FSTEntry entry; + File::ScanDirectoryTree("User/Shaders", entry); + for (int i = 0; i < entry.children.size(); i++) + { + std::string name = entry.children[i].virtualName.c_str(); + if (!stricmp(name.substr(name.size() - 4).c_str(), ".txt")) + name = name.substr(0, name.size() - 4); + m_PostShaderCB->Append(wxT(name)); + } + } + else + { + File::CreateDir("User/Shaders"); + } + + wxString shader = wxT(g_Config.sPostProcessingShader.c_str()); + if (shader == "") + shader = "(off)"; + m_PostShaderCB->SetStringSelection(shader); + // How to use the wxGridBagSizer: The wxGBPosition() must have a column and row sGeneral = new wxBoxSizer(wxVERTICAL); sBasic = new wxGridBagSizer(0, 0); @@ -300,6 +339,10 @@ void ConfigDialog::CreateGUIControls() sEnhancements->Add(MSAAText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); sEnhancements->Add(m_MSAAModeCB, wxGBPosition(1, 1), wxGBSpan(1, 2), wxALL, 5); sEnhancements->Add(m_ForceFiltering, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5); + sEnhancements->Add(PostShaderText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); + sEnhancements->Add(m_PostShaderCB, wxGBPosition(3, 1), wxGBSpan(1, 1), wxALL, 5); + sEnhancements->Add(m_ReloadShader, wxGBPosition(3, 2), wxGBSpan(1, 1), wxALL, 5); + sEnhancements->Add(m_EditShader, wxGBPosition(3, 3), wxGBSpan(1, 1), wxALL, 5); sbEnhancements->Add(sEnhancements); sGeneral->Add(sbEnhancements, 0, wxEXPAND|wxALL, 5); m_PageGeneral->SetSizer(sGeneral); @@ -475,6 +518,38 @@ void ConfigDialog::AboutClick(wxCommandEvent& WXUNUSED (event)) _T("Dolphin OGL"), wxOK, this); } +void ConfigDialog::ReloadShaderClick(wxCommandEvent& WXUNUSED (event)) +{ + PostProcessing::ReloadShader(); +} + +void ConfigDialog::EditShaderClick(wxCommandEvent& WXUNUSED (event)) +{ + if (m_PostShaderCB->GetStringSelection() == "(off)") + return; + wxString shader = "User/Shaders/" + m_PostShaderCB->GetStringSelection() + ".txt"; + if (wxFileExists(shader)) + { + wxFileType* filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(_("txt")); + if (filetype == NULL) // From extension failed, trying with MIME type now + { + filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType(_("text/plain")); + if (filetype == NULL) // MIME type failed, aborting mission + { + PanicAlert("Filetype 'txt' is unknown! Will not open!"); + return; + } + } + wxString OpenCommand; + OpenCommand = filetype->GetOpenCommand(shader); + if (OpenCommand.IsEmpty()) + PanicAlert("Couldn't find open command for extension 'ini'!"); + else + if (wxExecute(OpenCommand, wxEXEC_ASYNC) == -1) + PanicAlert("wxExecute returned -1 on application run!"); + } +} + void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event) { switch (event.GetId()) @@ -546,6 +621,11 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event) g_Config.UpdateProjectionHack(); } break; + case ID_POSTSHADER: + g_Config.sPostProcessingShader = m_PostShaderCB->GetString(m_PostShaderCB->GetSelection()); + if (g_Config.sPostProcessingShader == "(off)") + g_Config.sPostProcessingShader = ""; + break; } UpdateGUI(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h index 39c1ecfd50..4b20cad874 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h @@ -84,6 +84,9 @@ class ConfigDialog : public wxDialog wxButton *m_About; wxButton *m_Close; + wxButton *m_ReloadShader; + wxButton *m_EditShader; + wxNotebook *m_Notebook; wxPanel *m_PageGeneral; wxPanel *m_PageAdvanced; @@ -103,7 +106,8 @@ class ConfigDialog : public wxDialog wxArrayString arrayStringFor_MaxAnisotropyCB; wxChoice *m_MaxAnisotropyCB; wxArrayString arrayStringFor_MSAAModeCB, arrayStringFor_PhackvalueCB; - wxChoice *m_MSAAModeCB, *m_PhackvalueCB; + wxArrayString arrayStringFor_PostShaderCB; + wxChoice *m_MSAAModeCB, *m_PhackvalueCB, *m_PostShaderCB; wxCheckBox *m_ShowFPS; wxCheckBox *m_ShaderErrors; @@ -194,6 +198,10 @@ class ConfigDialog : public wxDialog ID_DSTALPHAPASS, ID_RADIO_COPYEFBTORAM, ID_RADIO_COPYEFBTOGL, + ID_POSTSHADER, + ID_POSTSHADERTEXT, + ID_RELOADSHADER, + ID_EDITSHADER, }; void OnClose(wxCloseEvent& event); @@ -201,6 +209,8 @@ class ConfigDialog : public wxDialog void UpdateHack(); void AboutClick(wxCommandEvent& event); + void ReloadShaderClick(wxCommandEvent& event); + void EditShaderClick(wxCommandEvent& event); void GeneralSettingsChanged(wxCommandEvent& event); void AdvancedSettingsChanged(wxCommandEvent& event); }; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index dfa80a31d8..1b8107696e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -220,12 +220,8 @@ bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrpr const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts); if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) { - if (s_displayCompileAlert) { - PanicAlert("Failed to create pixel shader"); - s_displayCompileAlert = false; - } cgDestroyProgram(tempprog); - ERROR_LOG(VIDEO, "Failed to create ps %s:", cgGetLastListing(g_cgcontext)); + ERROR_LOG(VIDEO, "Failed to compile ps %s:", cgGetLastListing(g_cgcontext)); ERROR_LOG(VIDEO, pstrprogram); return false; } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp index c0c2e497cc..ccd6d80ba0 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp @@ -38,16 +38,20 @@ void Shutdown() s_shader.Destroy(); } -void ApplyShader() +void ReloadShader() +{ + s_currentShader = ""; +} + +bool ApplyShader() { -#ifdef _WIN32 - if (GetAsyncKeyState(VK_LSHIFT)) - s_currentShader = ""; -#endif if (s_currentShader != "User/Shaders/" + g_Config.sPostProcessingShader + ".txt") { // Set immediately to prevent endless recompiles on failure. - s_currentShader = "User/Shaders/" + g_Config.sPostProcessingShader + ".txt"; + if (!g_Config.sPostProcessingShader.empty()) + s_currentShader = "User/Shaders/" + g_Config.sPostProcessingShader + ".txt"; + else + s_currentShader.clear(); s_shader.Destroy(); @@ -66,22 +70,20 @@ void ApplyShader() ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str()); } } - else - { - ERROR_LOG(VIDEO, "No post-processing shader selected."); - } } - if (s_shader.glprogid == 0) + if (s_shader.glprogid != 0) { - ERROR_LOG(VIDEO, "WTF"); + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_shader.glprogid); + return true; } else { - glEnable(GL_FRAGMENT_PROGRAM_ARB); + glDisable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + return false; } - // If anything went wrong above, glprogid will be 0, which is OK. - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_shader.glprogid); } } // namespace diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h index c834d6931f..3666750f02 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h @@ -27,7 +27,9 @@ namespace PostProcessing void Init(); void Shutdown(); -void ApplyShader(); +void ReloadShader(); +// Returns false if no shader was applied. +bool ApplyShader(); } // namespace diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 2ab29c1ed1..eb3cee743b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -179,10 +179,10 @@ void SetDefaultRectTexParams() void HandleCgError(CGcontext ctx, CGerror err, void* appdata) { - ERROR_LOG(VIDEO, "Cg error: %s", cgGetErrorString(err)); + DEBUG_LOG(VIDEO, "Cg error: %s", cgGetErrorString(err)); const char* listing = cgGetLastListing(g_cgcontext); if (listing != NULL) { - ERROR_LOG(VIDEO, " last listing: %s", listing); + DEBUG_LOG(VIDEO, " last listing: %s", listing); } } @@ -957,15 +957,28 @@ void Renderer::Swap(const TRectangle& rc) glDrawArrays(GL_QUADS, 0, 4); */ - // Here's an opportunity to bind a fragment shader to do post processing. - PostProcessing::ApplyShader(); + // We must call ApplyShader here even if no post proc is selected - it takes + // care of disabling it in that case. It returns false in case of no post processing. + if (PostProcessing::ApplyShader()) + { + glBegin(GL_QUADS); + glTexCoord2f(0, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); glVertex2f(-1, -1); + glTexCoord2f(0, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); glVertex2f(-1, 1); + glTexCoord2f(u_max, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); glVertex2f( 1, 1); + glTexCoord2f(u_max, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); glVertex2f( 1, -1); + glEnd(); - glBegin(GL_QUADS); - glTexCoord2f(0, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); glVertex2f(-1, -1); - glTexCoord2f(0, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); glVertex2f(-1, 1); - glTexCoord2f(u_max, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); glVertex2f( 1, 1); - glTexCoord2f(u_max, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); glVertex2f( 1, -1); - glEnd(); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + } + else + { + glBegin(GL_QUADS); + glTexCoord2f(0, v_min); glVertex2f(-1, -1); + glTexCoord2f(0, v_max); glVertex2f(-1, 1); + glTexCoord2f(u_max, v_max); glVertex2f( 1, 1); + glTexCoord2f(u_max, v_min); glVertex2f( 1, -1); + glEnd(); + } glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); TextureMngr::DisableStage(0);