Merge pull request #1817 from Armada651/custom-anaglyph
PostProcessing: Add support for user-supplied anaglyph shaders.
This commit is contained in:
commit
53a9df10f9
|
@ -0,0 +1,18 @@
|
|||
// Anaglyph Red-Cyan shader based on Dubois algorithm
|
||||
// Constants taken from the paper:
|
||||
// "Conversion of a Stereo Pair to Anaglyph with
|
||||
// the Least-Squares Projection Method"
|
||||
// Eric Dubois, March 2009
|
||||
|
||||
void main()
|
||||
{
|
||||
float4 c0 = SampleLayer(0);
|
||||
float4 c1 = SampleLayer(1);
|
||||
mat3 l = mat3( 0.437, 0.449, 0.164,
|
||||
-0.062,-0.062,-0.024,
|
||||
-0.048,-0.050,-0.017);
|
||||
mat3 r = mat3(-0.011,-0.032,-0.007,
|
||||
0.377, 0.761, 0.009,
|
||||
-0.026,-0.093, 1.234);
|
||||
SetOutput(float4(c0.rgb * l + c1.rgb * r, c0.a));
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// Anaglyph Red-Cyan shader without compensation
|
||||
|
||||
void main()
|
||||
{
|
||||
float4 c0 = SampleLayer(0);
|
||||
float4 c1 = SampleLayer(1);
|
||||
SetOutput(float4(c0.r, c1.gb, c0.a));
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Anaglyph Red-Cyan grayscale shader
|
||||
|
||||
void main()
|
||||
{
|
||||
float4 c0 = SampleLayer(0);
|
||||
float avg0 = (c0.r + c0.g + c0.b) / 3.0;
|
||||
float4 c1 = SampleLayer(1);
|
||||
float avg1 = (c1.r + c1.g + c1.b) / 3.0;
|
||||
SetOutput(float4(avg0, avg1, avg1, c0.a));
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// Anaglyph Red-Cyan luma grayscale shader
|
||||
// Info: http://www.oreillynet.com/cs/user/view/cs_msg/8691
|
||||
|
||||
void main()
|
||||
{
|
||||
float3 luma = float3(0.222, 0.707, 0.071);
|
||||
float4 c0 = SampleLayer(0);
|
||||
float avg0 = dot(c0.rgb, luma);
|
||||
float4 c1 = SampleLayer(1);
|
||||
float avg1 = dot(c1.rgb, luma);
|
||||
SetOutput(float4(avg0, avg1, avg1, c0.a));
|
||||
}
|
|
@ -74,6 +74,7 @@
|
|||
#define WII_SYSCONF_DIR "shared2" DIR_SEP "sys"
|
||||
#define WII_WC24CONF_DIR "shared2" DIR_SEP "wc24"
|
||||
#define THEMES_DIR "Themes"
|
||||
#define ANAGLYPH_DIR "Anaglyph"
|
||||
|
||||
// Filenames
|
||||
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
|
||||
|
|
|
@ -395,29 +395,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
|
|||
}
|
||||
|
||||
// postproc shader
|
||||
if (vconfig.backend_info.PPShaders.size())
|
||||
if (vconfig.backend_info.bSupportsPostProcessing)
|
||||
{
|
||||
wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5);
|
||||
choice_ppshader = new wxChoice(page_enh, wxID_ANY);
|
||||
RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc));
|
||||
choice_ppshader->AppendString(_("(off)"));
|
||||
|
||||
button_config_pp = new wxButton(page_enh, wxID_ANY, _("Config"));
|
||||
|
||||
for (const std::string& shader : vconfig.backend_info.PPShaders)
|
||||
{
|
||||
choice_ppshader->AppendString(StrToWxStr(shader));
|
||||
}
|
||||
|
||||
if (vconfig.sPostProcessingShader.empty() || vconfig.iStereoMode == STEREO_ANAGLYPH)
|
||||
choice_ppshader->Select(0);
|
||||
else
|
||||
choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader));
|
||||
|
||||
// Should the configuration button be loaded by default?
|
||||
PostProcessingShaderConfiguration postprocessing_shader;
|
||||
postprocessing_shader.LoadShader(vconfig.sPostProcessingShader);
|
||||
button_config_pp->Enable(postprocessing_shader.HasOptions());
|
||||
PopulatePostProcessingShaders();
|
||||
|
||||
choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this);
|
||||
button_config_pp->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ConfigurePPShader, this);
|
||||
|
@ -745,3 +730,38 @@ void VideoConfigDiag::CreateDescriptionArea(wxPanel* const page, wxBoxSizer* con
|
|||
// Store description text object for later lookup
|
||||
desc_texts.insert(std::pair<wxWindow*,wxStaticText*>(page, desc_text));
|
||||
}
|
||||
|
||||
void VideoConfigDiag::PopulatePostProcessingShaders()
|
||||
{
|
||||
std::vector<std::string> &shaders = (vconfig.iStereoMode == STEREO_ANAGLYPH) ?
|
||||
vconfig.backend_info.AnaglyphShaders : vconfig.backend_info.PPShaders;
|
||||
|
||||
if (shaders.empty())
|
||||
return;
|
||||
|
||||
choice_ppshader->AppendString(_("(off)"));
|
||||
|
||||
for (const std::string& shader : shaders)
|
||||
{
|
||||
choice_ppshader->AppendString(StrToWxStr(shader));
|
||||
}
|
||||
|
||||
if (!choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader)))
|
||||
{
|
||||
// Invalid shader, reset it to default
|
||||
choice_ppshader->Select(0);
|
||||
|
||||
if (vconfig.iStereoMode == STEREO_ANAGLYPH)
|
||||
{
|
||||
vconfig.sPostProcessingShader = "dubois";
|
||||
choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader));
|
||||
}
|
||||
else
|
||||
vconfig.sPostProcessingShader.clear();
|
||||
}
|
||||
|
||||
// Should the configuration button be loaded by default?
|
||||
PostProcessingShaderConfiguration postprocessing_shader;
|
||||
postprocessing_shader.LoadShader(vconfig.sPostProcessingShader);
|
||||
button_config_pp->Enable(postprocessing_shader.HasOptions());
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ protected:
|
|||
// Should we enable the configuration button?
|
||||
PostProcessingShaderConfiguration postprocessing_shader;
|
||||
postprocessing_shader.LoadShader(vconfig.sPostProcessingShader);
|
||||
button_config_pp->Enable(postprocessing_shader.HasOptions() && vconfig.iStereoMode != STEREO_ANAGLYPH);
|
||||
button_config_pp->Enable(postprocessing_shader.HasOptions());
|
||||
|
||||
ev.Skip();
|
||||
}
|
||||
|
@ -181,15 +181,10 @@ protected:
|
|||
|
||||
void Event_StereoMode(wxCommandEvent &ev)
|
||||
{
|
||||
if (ev.GetInt() == STEREO_ANAGLYPH && vconfig.backend_info.PPShaders.size())
|
||||
if (vconfig.backend_info.bSupportsPostProcessing)
|
||||
{
|
||||
// Anaglyph overrides post-processing shaders
|
||||
choice_ppshader->Select(0);
|
||||
choice_ppshader->Enable(false);
|
||||
}
|
||||
else if (vconfig.backend_info.PPShaders.size())
|
||||
{
|
||||
choice_ppshader->Enable(true);
|
||||
choice_ppshader->Clear();
|
||||
}
|
||||
|
||||
ev.Skip();
|
||||
|
@ -214,6 +209,10 @@ protected:
|
|||
virtual_xfb->Enable(vconfig.bUseXFB);
|
||||
real_xfb->Enable(vconfig.bUseXFB);
|
||||
|
||||
// Repopulating the post-processing shaders can't be done from an event
|
||||
if (choice_ppshader && choice_ppshader->IsEmpty())
|
||||
PopulatePostProcessingShaders();
|
||||
|
||||
// Things which shouldn't be changed during emulation
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
|
@ -251,6 +250,7 @@ protected:
|
|||
void Evt_EnterControl(wxMouseEvent& ev);
|
||||
void Evt_LeaveControl(wxMouseEvent& ev);
|
||||
void CreateDescriptionArea(wxPanel* const page, wxBoxSizer* const sizer);
|
||||
void PopulatePostProcessingShaders();
|
||||
|
||||
wxChoice* choice_backend;
|
||||
wxChoice* choice_adapter;
|
||||
|
|
|
@ -65,6 +65,7 @@ void CreateDirectories()
|
|||
File::CreateFullPath(File::GetUserPath(D_MAPS_IDX));
|
||||
File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX));
|
||||
File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX));
|
||||
File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + ANAGLYPH_DIR DIR_SEP);
|
||||
File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX));
|
||||
File::CreateFullPath(File::GetUserPath(D_THEMES_IDX));
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ void InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsOversizedViewports = false;
|
||||
g_Config.backend_info.bSupportsGeometryShaders = true;
|
||||
g_Config.backend_info.bSupports3DVision = true;
|
||||
g_Config.backend_info.bSupportsPostProcessing = false;
|
||||
|
||||
IDXGIFactory* factory;
|
||||
IDXGIAdapter* ad;
|
||||
|
@ -133,6 +134,7 @@ void InitBackendInfo()
|
|||
|
||||
// Clear ppshaders string vector
|
||||
g_Config.backend_info.PPShaders.clear();
|
||||
g_Config.backend_info.AnaglyphShaders.clear();
|
||||
|
||||
DX11::D3D::UnloadDXGI();
|
||||
DX11::D3D::UnloadD3D();
|
||||
|
|
|
@ -36,29 +36,8 @@ static const char s_vertex_shader[] =
|
|||
" uv0 = rawpos * src_rect.zw + src_rect.xy;\n"
|
||||
"}\n";
|
||||
|
||||
// Anaglyph Red-Cyan shader based on Dubois algorithm
|
||||
// Constants taken from the paper:
|
||||
// "Conversion of a Stereo Pair to Anaglyph with
|
||||
// the Least-Squares Projection Method"
|
||||
// Eric Dubois, March 2009
|
||||
static const char s_anaglyph_shader[] =
|
||||
"void main() {\n"
|
||||
" vec4 c0 = SampleLayer(0);\n"
|
||||
" vec4 c1 = SampleLayer(1);\n"
|
||||
" mat3 l = mat3( 0.437, 0.449, 0.164,\n"
|
||||
" -0.062,-0.062,-0.024,\n"
|
||||
" -0.048,-0.050,-0.017);\n"
|
||||
" mat3 r = mat3(-0.011,-0.032,-0.007,\n"
|
||||
" 0.377, 0.761, 0.009,\n"
|
||||
" -0.026,-0.093, 1.234);\n"
|
||||
" SetOutput(vec4(c0.rgb * l + c1.rgb * r, c0.a));\n"
|
||||
"}\n";
|
||||
|
||||
static const char s_default_shader[] = "void main() { SetOutput(Sample()); }\n";
|
||||
|
||||
OpenGLPostProcessing::OpenGLPostProcessing()
|
||||
: m_initialized(false)
|
||||
, m_anaglyph(false)
|
||||
{
|
||||
CreateHeader();
|
||||
|
||||
|
@ -183,23 +162,14 @@ void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle
|
|||
void OpenGLPostProcessing::ApplyShader()
|
||||
{
|
||||
// shader didn't changed
|
||||
if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader &&
|
||||
((g_ActiveConfig.iStereoMode == STEREO_ANAGLYPH) == m_anaglyph))
|
||||
if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader)
|
||||
return;
|
||||
|
||||
m_shader.Destroy();
|
||||
m_uniform_bindings.clear();
|
||||
|
||||
// load shader code
|
||||
std::string code = "";
|
||||
if (g_ActiveConfig.iStereoMode == STEREO_ANAGLYPH)
|
||||
code = s_anaglyph_shader;
|
||||
else if (g_ActiveConfig.sPostProcessingShader != "")
|
||||
code = m_config.LoadShader();
|
||||
|
||||
if (code == "")
|
||||
code = s_default_shader;
|
||||
|
||||
std::string code = m_config.LoadShader();
|
||||
code = LoadShaderOptions(code);
|
||||
|
||||
const char* vertex_shader = s_vertex_shader;
|
||||
|
@ -211,8 +181,8 @@ void OpenGLPostProcessing::ApplyShader()
|
|||
if (!ProgramShaderCache::CompileShader(m_shader, vertex_shader, code.c_str()))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", m_config.GetShader().c_str());
|
||||
|
||||
code = LoadShaderOptions(s_default_shader);
|
||||
g_ActiveConfig.sPostProcessingShader.clear();
|
||||
code = m_config.LoadShader();
|
||||
ProgramShaderCache::CompileShader(m_shader, vertex_shader, code.c_str());
|
||||
}
|
||||
|
||||
|
@ -244,7 +214,6 @@ void OpenGLPostProcessing::ApplyShader()
|
|||
std::string glsl_name = "option_" + it.first;
|
||||
m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str());
|
||||
}
|
||||
m_anaglyph = g_ActiveConfig.iStereoMode == STEREO_ANAGLYPH;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ public:
|
|||
|
||||
private:
|
||||
bool m_initialized;
|
||||
bool m_anaglyph;
|
||||
SHADER m_shader;
|
||||
GLuint m_uniform_resolution;
|
||||
GLuint m_uniform_src_rect;
|
||||
|
|
|
@ -95,14 +95,14 @@ std::string VideoBackend::GetDisplayName() const
|
|||
return "OpenGL";
|
||||
}
|
||||
|
||||
static void GetShaders(std::vector<std::string> &shaders)
|
||||
static void GetShaders(std::vector<std::string> &shaders, const std::string &sub_dir = "")
|
||||
{
|
||||
std::set<std::string> already_found;
|
||||
|
||||
shaders.clear();
|
||||
static const std::string directories[] = {
|
||||
File::GetUserPath(D_SHADERS_IDX),
|
||||
File::GetSysDirectory() + SHADERS_DIR DIR_SEP,
|
||||
const std::string directories[] = {
|
||||
File::GetUserPath(D_SHADERS_IDX) + sub_dir,
|
||||
File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir,
|
||||
};
|
||||
for (auto& directory : directories)
|
||||
{
|
||||
|
@ -139,6 +139,7 @@ static void InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsOversizedViewports = true;
|
||||
g_Config.backend_info.bSupportsGeometryShaders = true;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
g_Config.backend_info.bSupportsPostProcessing = true;
|
||||
|
||||
g_Config.backend_info.Adapters.clear();
|
||||
|
||||
|
@ -148,6 +149,7 @@ static void InitBackendInfo()
|
|||
|
||||
// pp shaders
|
||||
GetShaders(g_Config.backend_info.PPShaders);
|
||||
GetShaders(g_Config.backend_info.AnaglyphShaders, std::string(ANAGLYPH_DIR DIR_SEP));
|
||||
}
|
||||
|
||||
void VideoBackend::ShowConfig(void *_hParent)
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
|
||||
static const char s_default_shader[] = "void main() { SetOutput(Sample()); }\n";
|
||||
|
||||
PostProcessingShaderImplementation::PostProcessingShaderImplementation()
|
||||
{
|
||||
m_timer.Start();
|
||||
|
@ -30,20 +32,29 @@ std::string PostProcessingShaderConfiguration::LoadShader(std::string shader)
|
|||
shader = g_ActiveConfig.sPostProcessingShader;
|
||||
m_current_shader = shader;
|
||||
|
||||
const std::string sub_dir = (g_Config.iStereoMode == STEREO_ANAGLYPH) ? ANAGLYPH_DIR DIR_SEP : "";
|
||||
|
||||
// loading shader code
|
||||
std::string code;
|
||||
std::string path = File::GetUserPath(D_SHADERS_IDX) + shader + ".glsl";
|
||||
std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl";
|
||||
|
||||
if (!File::Exists(path))
|
||||
if (shader == "")
|
||||
{
|
||||
// Fallback to shared user dir
|
||||
path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + shader + ".glsl";
|
||||
code = s_default_shader;
|
||||
}
|
||||
|
||||
if (!File::ReadFileToString(path, code))
|
||||
else
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
|
||||
return "";
|
||||
if (!File::Exists(path))
|
||||
{
|
||||
// Fallback to shared user dir
|
||||
path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl";
|
||||
}
|
||||
|
||||
if (!File::ReadFileToString(path, code))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
|
||||
code = s_default_shader;
|
||||
}
|
||||
}
|
||||
|
||||
LoadOptions(code);
|
||||
|
|
|
@ -147,6 +147,7 @@ struct VideoConfig final
|
|||
std::vector<std::string> Adapters; // for D3D
|
||||
std::vector<std::string> AAModes;
|
||||
std::vector<std::string> PPShaders; // post-processing shaders
|
||||
std::vector<std::string> AnaglyphShaders; // anaglyph shaders
|
||||
|
||||
bool bSupportsExclusiveFullscreen;
|
||||
bool bSupportsDualSourceBlend;
|
||||
|
@ -158,6 +159,7 @@ struct VideoConfig final
|
|||
bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon
|
||||
bool bSupportsBBox;
|
||||
bool bSupportsGSInstancing; // Needed by GeometryShaderGen, so must stay in VideoCommon
|
||||
bool bSupportsPostProcessing;
|
||||
} backend_info;
|
||||
|
||||
// Utility
|
||||
|
|
Loading…
Reference in New Issue