diff --git a/Data/User/Shaders/bad_bloom.txt b/Data/User/Shaders/bad_bloom.txt new file mode 100644 index 0000000000..720786754a --- /dev/null +++ b/Data/User/Shaders/bad_bloom.txt @@ -0,0 +1,45 @@ +uniform samplerRECT samp0 : register(s0); + +const float2 samples[8] = { + float2(-1.5, -1.5), + float2(-2.5, 0), + float2(-1.5, 1.5), + float2(0, 2.5), + float2(1.5, 1.5), + float2(2.5, 0), + float2(1.5, -1.5), + float2(0, -2.5), +}; + +void main(out float4 ocol0 : COLOR0, in float2 uv0 : TEXCOORD0) +{ + float4 c_center = texRECT(samp0, uv0).rgba; + + float4 bloom_sum = float4(0.0, 0.0, 0.0, 0.0); + uv0 += float2(0.3, 0.3); + float radius1 = 1.3; + bloom_sum += texRECT(samp0, uv0 + float2(-1.5, -1.5) * radius1); + bloom_sum += texRECT(samp0, uv0 + float2(-2.5, 0) * radius1); + bloom_sum += texRECT(samp0, uv0 + float2(-1.5, 1.5) * radius1); + bloom_sum += texRECT(samp0, uv0 + float2(0, 2.5) * radius1); + bloom_sum += texRECT(samp0, uv0 + float2(1.5, 1.5) * radius1); + bloom_sum += texRECT(samp0, uv0 + float2(2.5, 0) * radius1); + bloom_sum += texRECT(samp0, uv0 + float2(1.5, -1.5) * radius1); + bloom_sum += texRECT(samp0, uv0 + float2(0, -2.5) * radius1); + + float radius2 = 4.6; + bloom_sum += texRECT(samp0, uv0 + float2(-1.5, -1.5) * radius2); + bloom_sum += texRECT(samp0, uv0 + float2(-2.5, 0) * radius2); + bloom_sum += texRECT(samp0, uv0 + float2(-1.5, 1.5) * radius2); + bloom_sum += texRECT(samp0, uv0 + float2(0, 2.5) * radius2); + bloom_sum += texRECT(samp0, uv0 + float2(1.5, 1.5) * radius2); + bloom_sum += texRECT(samp0, uv0 + float2(2.5, 0) * radius2); + bloom_sum += texRECT(samp0, uv0 + float2(1.5, -1.5) * radius2); + bloom_sum += texRECT(samp0, uv0 + float2(0, -2.5) * radius2); + + bloom_sum *= 0.07; + bloom_sum -= float4(0.3, 0.3, 0.3, 0.3); + bloom_sum = max(bloom_sum, float4(0,0,0,0)); + + ocol0 = c_center * 0.7 + bloom_sum; +} diff --git a/Data/User/Shaders/invert.txt b/Data/User/Shaders/invert.txt new file mode 100644 index 0000000000..efd57def22 --- /dev/null +++ b/Data/User/Shaders/invert.txt @@ -0,0 +1,7 @@ +uniform samplerRECT samp0 : register(s0); + +void main(out float4 ocol0 : COLOR0, in float2 uv0 : TEXCOORD0) +{ + float4 c0 = texRECT(samp0, uv0).rgba; + ocol0 = float4(1.0, 1.0, 1.0, 1.0) - c0; +} diff --git a/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj b/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj index 2f6ad843d2..316011c9f2 100644 --- a/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj +++ b/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj @@ -752,6 +752,14 @@ RelativePath=".\Src\PixelShaderCache.h" > + + + + diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp index 19345a0f5d..491f1d6f75 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp @@ -77,6 +77,7 @@ void Config::Load() iniFile.Get("Enhancements", "ForceFiltering", &bForceFiltering, 0); iniFile.Get("Enhancements", "MaxAnisotropy", &iMaxAnisotropy, 3); // NOTE - this is x in (1 << x) + iniFile.Get("Enhancements", "PostProcessingShader", &sPostProcessingShader, ""); iniFile.Get("Hacks", "EFBCopyDisable", &bEFBCopyDisable, 0); iniFile.Get("Hacks", "EFBCopyDisableHotKey", &bEFBCopyDisableHotKey, 0); @@ -169,6 +170,7 @@ void Config::Save() iniFile.Set("Enhancements", "ForceFiltering", bForceFiltering); iniFile.Set("Enhancements", "MaxAnisotropy", iMaxAnisotropy); + iniFile.Set("Enhancements", "PostProcessingShader", sPostProcessingShader); iniFile.Set("Hacks", "EFBCopyDisable", bEFBCopyDisable); iniFile.Set("Hacks", "EFBCopyDisableHotKey", bEFBCopyDisableHotKey); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.h b/Source/Plugins/Plugin_VideoOGL/Src/Config.h index b151a4a8ac..ceede1917a 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Config.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.h @@ -66,6 +66,7 @@ struct Config int iMultisampleMode; bool bForceFiltering; int iMaxAnisotropy; + std::string sPostProcessingShader; // Information bool bShowFPS; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp new file mode 100644 index 0000000000..c0c2e497cc --- /dev/null +++ b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "VideoCommon.h" +#include "FileUtil.h" +#include "Config.h" +#include "GLUtil.h" +#include "PostProcessing.h" +#include "PixelShaderCache.h" + +namespace PostProcessing +{ + +static std::string s_currentShader; +static FRAGMENTSHADER s_shader; + +void Init() +{ + s_currentShader = ""; +} + +void Shutdown() +{ + s_shader.Destroy(); +} + +void 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"; + + s_shader.Destroy(); + + if (!s_currentShader.empty()) + { + std::string code; + if (File::ReadFileToString(true, s_currentShader.c_str(), code)) + { + if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str())) + { + ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str()); + } + } + else + { + 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) + { + ERROR_LOG(VIDEO, "WTF"); + } + else + { + glEnable(GL_FRAGMENT_PROGRAM_ARB); + } + // 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 new file mode 100644 index 0000000000..c834d6931f --- /dev/null +++ b/Source/Plugins/Plugin_VideoOGL/Src/PostProcessing.h @@ -0,0 +1,34 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _POSTPROCESSING_H_ +#define _POSTPROCESSING_H_ + +#include "VideoCommon.h" +#include "GLUtil.h" + +namespace PostProcessing +{ + +void Init(); +void Shutdown(); + +void ApplyShader(); + +} // namespace + +#endif // _POSTPROCESSING_H_ diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 7e9b6f48af..d0ed2be5ac 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -51,6 +51,7 @@ #include "VertexShaderManager.h" #include "VertexLoaderManager.h" #include "VertexLoader.h" +#include "PostProcessing.h" #include "XFB.h" #include "OnScreenDisplay.h" #include "Timer.h" @@ -955,7 +956,8 @@ void Renderer::Swap(const TRectangle& rc) */ // Here's an opportunity to bind a fragment shader to do post processing. - + PostProcessing::ApplyShader(); + glBegin(GL_QUADS); glTexCoord2f(0, v_min); glVertex2f(-1, -1); glTexCoord2f(0, v_max); glVertex2f(-1, 1); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index f3f2dcb3bd..167663db4f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -81,6 +81,7 @@ Make AA apply instantly during gameplay if possible #include "XFB.h" #include "XFBConvert.h" #include "TextureConverter.h" +#include "PostProcessing.h" #include "OnScreenDisplay.h" #include "Setup.h" @@ -353,6 +354,7 @@ void Video_Prepare(void) VertexShaderManager::Init(); PixelShaderCache::Init(); PixelShaderManager::Init(); + PostProcessing::Init(); GL_REPORT_ERRORD(); VertexLoaderManager::Init(); TextureConverter::Init(); @@ -362,6 +364,7 @@ void Video_Prepare(void) void Shutdown(void) { Fifo_Shutdown(); + PostProcessing::Shutdown(); TextureConverter::Shutdown(); VertexLoaderManager::Shutdown(); VertexShaderCache::Shutdown();