diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 86d592b8c..9193dcb5e 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -131,10 +131,13 @@ void Config::ReadValues() { sdl2_config->GetInteger("Renderer", "render_3d", 0)); Settings::values.factor_3d = static_cast(sdl2_config->GetInteger("Renderer", "factor_3d", 0)); - Settings::values.pp_shader_name = sdl2_config->GetString( - "Renderer", "pp_shader_name", - (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph) ? "dubois (builtin)" - : "none (builtin)"); + std::string default_shader = "none (builtin)"; + if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph) + default_shader = "dubois (builtin)"; + else if (Settings::values.render_3d == Settings::StereoRenderOption::Interlaced) + default_shader = "horizontal (builtin)"; + Settings::values.pp_shader_name = + sdl2_config->GetString("Renderer", "pp_shader_name", default_shader); Settings::values.filter_mode = sdl2_config->GetBoolean("Renderer", "filter_mode", true); Settings::values.bg_red = static_cast(sdl2_config->GetReal("Renderer", "bg_red", 0.0)); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index d646823e2..79481dc75 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -137,7 +137,7 @@ bg_blue = bg_green = # Whether and how Stereoscopic 3D should be rendered -# 0 (default): Off, 1: Side by Side, 2: Anaglyph +# 0 (default): Off, 1: Side by Side, 2: Anaglyph, 3: Interlaced render_3d = # Change 3D Intensity diff --git a/src/citra_qt/configuration/configure_enhancements.cpp b/src/citra_qt/configuration/configure_enhancements.cpp index 677f868c2..97cc1f53d 100644 --- a/src/citra_qt/configuration/configure_enhancements.cpp +++ b/src/citra_qt/configuration/configure_enhancements.cpp @@ -21,8 +21,7 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent) connect(ui->render_3d_combobox, static_cast(&QComboBox::currentIndexChanged), this, [this](int currentIndex) { - updateShaders(static_cast(currentIndex) == - Settings::StereoRenderOption::Anaglyph); + updateShaders(static_cast(currentIndex)); }); connect(ui->bg_button, &QPushButton::clicked, this, [this] { @@ -49,7 +48,7 @@ void ConfigureEnhancements::SetConfiguration() { ui->resolution_factor_combobox->setCurrentIndex(Settings::values.resolution_factor); ui->render_3d_combobox->setCurrentIndex(static_cast(Settings::values.render_3d)); ui->factor_3d->setValue(Settings::values.factor_3d); - updateShaders(Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph); + updateShaders(Settings::values.render_3d); ui->toggle_linear_filter->setChecked(Settings::values.filter_mode); ui->layout_combobox->setCurrentIndex(static_cast(Settings::values.layout_option)); ui->swap_screen->setChecked(Settings::values.swap_screen); @@ -64,17 +63,20 @@ void ConfigureEnhancements::SetConfiguration() { ui->bg_button->setIcon(color_icon); } -void ConfigureEnhancements::updateShaders(bool anaglyph) { +void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_option) { ui->shader_combobox->clear(); - if (anaglyph) + if (stereo_option == Settings::StereoRenderOption::Anaglyph) ui->shader_combobox->addItem("dubois (builtin)"); + else if (stereo_option == Settings::StereoRenderOption::Interlaced) + ui->shader_combobox->addItem("horizontal (builtin)"); else ui->shader_combobox->addItem("none (builtin)"); ui->shader_combobox->setCurrentIndex(0); - for (const auto& shader : OpenGL::GetPostProcessingShaderList(anaglyph)) { + for (const auto& shader : OpenGL::GetPostProcessingShaderList( + stereo_option == Settings::StereoRenderOption::Anaglyph)) { ui->shader_combobox->addItem(QString::fromStdString(shader)); if (Settings::values.pp_shader_name == shader) ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1); diff --git a/src/citra_qt/configuration/configure_enhancements.h b/src/citra_qt/configuration/configure_enhancements.h index 422c1dc35..7155140bd 100644 --- a/src/citra_qt/configuration/configure_enhancements.h +++ b/src/citra_qt/configuration/configure_enhancements.h @@ -6,6 +6,10 @@ #include +namespace Settings { +enum class StereoRenderOption; +} + namespace Ui { class ConfigureEnhancements; } @@ -22,7 +26,7 @@ public: void SetConfiguration(); private: - void updateShaders(bool anaglyph); + void updateShaders(Settings::StereoRenderOption stereo_option); Ui::ConfigureEnhancements* ui; QColor bg_color; diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui index bb677dabb..b268a50fe 100644 --- a/src/citra_qt/configuration/configure_enhancements.ui +++ b/src/citra_qt/configuration/configure_enhancements.ui @@ -152,6 +152,11 @@ Anaglyph + + + Interlaced + + diff --git a/src/core/settings.h b/src/core/settings.h index d7d351a4c..a0b0464f2 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -32,7 +32,7 @@ enum class MicInputType { Static, }; -enum class StereoRenderOption { Off, SideBySide, Anaglyph }; +enum class StereoRenderOption { Off, SideBySide, Anaglyph, Interlaced }; namespace NativeButton { enum Values { diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 7b7c73483..ecf0d7a68 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -238,6 +238,25 @@ void main() { } )"; +static const char fragment_shader_interlaced[] = R"( + +in vec2 frag_tex_coord; +out vec4 color; + +uniform vec4 o_resolution; + +uniform sampler2D color_texture; +uniform sampler2D color_texture_r; + +void main() { + float screen_row = o_resolution.x * frag_tex_coord.x; + if (int(screen_row) % 2 == 0) + color = texture(color_texture, frag_tex_coord); + else + color = texture(color_texture_r, frag_tex_coord); +} +)"; + /** * Vertex structure that the drawn screen rectangles are composed of. */ @@ -622,6 +641,19 @@ void RendererOpenGL::ReloadShader() { shader_data += shader_text; } } + } else if (Settings::values.render_3d == Settings::StereoRenderOption::Interlaced) { + if (Settings::values.pp_shader_name == "horizontal (builtin)") { + shader_data += fragment_shader_interlaced; + } else { + std::string shader_text = + OpenGL::GetPostProcessingShaderCode(true, Settings::values.pp_shader_name); + if (shader_text.empty()) { + // Should probably provide some information that the shader couldn't load + shader_data += fragment_shader_interlaced; + } else { + shader_data += shader_text; + } + } } else { if (Settings::values.pp_shader_name == "none (builtin)") { shader_data += fragment_shader; @@ -641,7 +673,8 @@ void RendererOpenGL::ReloadShader() { state.Apply(); uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix"); uniform_color_texture = glGetUniformLocation(shader.handle, "color_texture"); - if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph) { + if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph || + Settings::values.render_3d == Settings::StereoRenderOption::Interlaced) { uniform_color_texture_r = glGetUniformLocation(shader.handle, "color_texture_r"); } uniform_i_resolution = glGetUniformLocation(shader.handle, "i_resolution"); @@ -752,9 +785,9 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD * rotation. */ -void RendererOpenGL::DrawSingleScreenAnaglyphRotated(const ScreenInfo& screen_info_l, - const ScreenInfo& screen_info_r, float x, - float y, float w, float h) { +void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l, + const ScreenInfo& screen_info_r, float x, + float y, float w, float h) { const auto& texcoords = screen_info_l.display_texcoords; const std::array vertices = {{ @@ -822,8 +855,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) { // Bind texture in Texture Unit 0 glUniform1i(uniform_color_texture, 0); + const bool stereo_single_screen = + Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph || + Settings::values.render_3d == Settings::StereoRenderOption::Interlaced; + // Bind a second texture for the right eye if in Anaglyph mode - if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph) { + if (stereo_single_screen) { glUniform1i(uniform_color_texture_r, 1); } @@ -841,10 +878,10 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) { ((float)top_screen.left / 2) + ((float)layout.width / 2), (float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight()); - } else if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph) { - DrawSingleScreenAnaglyphRotated( - screen_infos[0], screen_infos[1], (float)top_screen.left, (float)top_screen.top, - (float)top_screen.GetWidth(), (float)top_screen.GetHeight()); + } else if (stereo_single_screen) { + DrawSingleScreenStereoRotated(screen_infos[0], screen_infos[1], (float)top_screen.left, + (float)top_screen.top, (float)top_screen.GetWidth(), + (float)top_screen.GetHeight()); } } glUniform1i(uniform_layer, 0); @@ -862,11 +899,11 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) { ((float)bottom_screen.left / 2) + ((float)layout.width / 2), (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight()); - } else if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph) { - DrawSingleScreenAnaglyphRotated(screen_infos[2], screen_infos[2], - (float)bottom_screen.left, (float)bottom_screen.top, - (float)bottom_screen.GetWidth(), - (float)bottom_screen.GetHeight()); + } else if (stereo_single_screen) { + DrawSingleScreenStereoRotated(screen_infos[2], screen_infos[2], + (float)bottom_screen.left, (float)bottom_screen.top, + (float)bottom_screen.GetWidth(), + (float)bottom_screen.GetHeight()); } } } diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 40c850b78..a9417853b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -77,9 +77,9 @@ private: const GPU::Regs::FramebufferConfig& framebuffer); void DrawScreens(const Layout::FramebufferLayout& layout); void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h); - void DrawSingleScreenAnaglyphRotated(const ScreenInfo& screen_info_l, - const ScreenInfo& screen_info_r, float x, float y, float w, - float h); + void DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l, + const ScreenInfo& screen_info_r, float x, float y, float w, + float h); void UpdateFramerate(); // Loads framebuffer from emulated memory into the display information structure