diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui index 83b85ba9a..862125783 100644 --- a/src/citra_qt/configuration/configure_enhancements.ui +++ b/src/citra_qt/configuration/configure_enhancements.ui @@ -7,7 +7,7 @@ 0 0 440 - 748 + 781 @@ -199,11 +199,11 @@ xBRZ - - - MMPX - - + + + MMPX + + @@ -239,6 +239,11 @@ Side by Side + + + Top Bottom + + Anaglyph diff --git a/src/common/settings.h b/src/common/settings.h index 6d3cbd98a..030797930 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -49,10 +49,11 @@ enum class LayoutOption : u32 { enum class StereoRenderOption : u32 { Off = 0, SideBySide = 1, - Anaglyph = 2, - Interlaced = 3, - ReverseInterlaced = 4, - CardboardVR = 5 + TopBottom = 2, + Anaglyph = 3, + Interlaced = 4, + ReverseInterlaced = 5, + CardboardVR = 6 }; // Which eye to render when 3d is off. 800px wide mode could be added here in the future, when diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index cdefdb541..0b32b5324 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -73,6 +73,13 @@ bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, uns framebuffer_x < layout.bottom_screen.right / 2) || (framebuffer_x >= (layout.bottom_screen.left / 2) + (layout.width / 2) && framebuffer_x < (layout.bottom_screen.right / 2) + (layout.width / 2)))); + } else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::TopBottom) { + return framebuffer_x >= layout.bottom_screen.left && + framebuffer_x < layout.bottom_screen.right && + ((framebuffer_y >= layout.bottom_screen.top / 2 && + framebuffer_y < layout.bottom_screen.bottom / 2) || + (framebuffer_y >= (layout.bottom_screen.top / 2) + (layout.height / 2) && + framebuffer_y < (layout.bottom_screen.bottom / 2) + (layout.height / 2))); } else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) { return (framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom && @@ -91,22 +98,35 @@ bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, uns std::tuple EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) const { if (new_x >= framebuffer_layout.width / 2) { - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { new_x -= framebuffer_layout.width / 2; - else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) + } else if (Settings::values.render_3d.GetValue() == + Settings::StereoRenderOption::CardboardVR) { new_x -= (framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2); + } } - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { - new_x = std::max(new_x, framebuffer_layout.bottom_screen.left / 2); - new_x = std::min(new_x, framebuffer_layout.bottom_screen.right / 2 - 1); - } else { - new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); - new_x = std::min(new_x, framebuffer_layout.bottom_screen.right - 1); + if (new_y >= framebuffer_layout.height / 2) { + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::TopBottom) { + new_y -= framebuffer_layout.height / 2; + } } - new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); - new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom - 1); + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { + new_x = std::clamp(new_x, framebuffer_layout.bottom_screen.left / 2, + framebuffer_layout.bottom_screen.right / 2 - 1); + } else { + new_x = std::clamp(new_x, framebuffer_layout.bottom_screen.left, + framebuffer_layout.bottom_screen.right - 1); + } + + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::TopBottom) { + new_y = std::clamp(new_y, framebuffer_layout.bottom_screen.top / 2, + framebuffer_layout.bottom_screen.bottom / 2 - 1); + } else { + new_y = std::clamp(new_y, framebuffer_layout.bottom_screen.top, + framebuffer_layout.bottom_screen.bottom - 1); + } return std::make_tuple(new_x, new_y); } @@ -122,17 +142,25 @@ void EmuWindow::CreateTouchState() { } bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { - if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) + if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { return false; + } if (framebuffer_x >= framebuffer_layout.width / 2) { - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { framebuffer_x -= framebuffer_layout.width / 2; - else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) + } else if (Settings::values.render_3d.GetValue() == + Settings::StereoRenderOption::CardboardVR) { framebuffer_x -= (framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2); + } } - std::lock_guard guard(touch_state->mutex); + if (framebuffer_y >= framebuffer_layout.height / 2) { + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::TopBottom) { + framebuffer_y -= framebuffer_layout.height / 2; + } + } + std::scoped_lock lock{touch_state->mutex}; if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { touch_state->touch_x = static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left / 2) / @@ -143,9 +171,17 @@ bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left) / (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); } - touch_state->touch_y = - static_cast(framebuffer_y - framebuffer_layout.bottom_screen.top) / - (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); + + if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::TopBottom) { + touch_state->touch_y = + static_cast(framebuffer_y - framebuffer_layout.bottom_screen.top / 2) / + (framebuffer_layout.bottom_screen.bottom / 2 - + framebuffer_layout.bottom_screen.top / 2); + } else { + touch_state->touch_y = + static_cast(framebuffer_y - framebuffer_layout.bottom_screen.top) / + (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); + } if (!framebuffer_layout.is_rotated) { std::swap(touch_state->touch_x, touch_state->touch_y); @@ -157,18 +193,20 @@ bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { } void EmuWindow::TouchReleased() { - std::lock_guard guard{touch_state->mutex}; + std::scoped_lock lock{touch_state->mutex}; touch_state->touch_pressed = false; touch_state->touch_x = 0; touch_state->touch_y = 0; } void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { - if (!touch_state->touch_pressed) + if (!touch_state->touch_pressed) { return; + } - if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) + if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); + } TouchPressed(framebuffer_x, framebuffer_y); } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index b0dcb1433..6a493c3fc 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -774,6 +774,15 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, top_screen_top, top_screen_width / 2, top_screen_height, orientation); break; } + case Settings::StereoRenderOption::TopBottom: { + DrawSingleScreen(screen_infos[0], top_screen_left, top_screen_top / 2, top_screen_width, + top_screen_height / 2, orientation); + glUniform1i(uniform_layer, 1); + DrawSingleScreen(screen_infos[1], top_screen_left, + static_cast((top_screen_top / 2) + (layout.height / 2)), + top_screen_width, top_screen_height / 2, orientation); + break; + } case Settings::StereoRenderOption::CardboardVR: { DrawSingleScreen(screen_infos[0], top_screen_left, top_screen_top, top_screen_width, top_screen_height, orientation); @@ -823,6 +832,15 @@ void RendererOpenGL::DrawBottomScreen(const Layout::FramebufferLayout& layout, bottom_screen_top, bottom_screen_width / 2, bottom_screen_height, orientation); break; } + case Settings::StereoRenderOption::TopBottom: { + DrawSingleScreen(screen_infos[2], bottom_screen_left, bottom_screen_top / 2, + bottom_screen_width, bottom_screen_height / 2, orientation); + glUniform1i(uniform_layer, 1); + DrawSingleScreen(screen_infos[2], bottom_screen_left, + static_cast((bottom_screen_top / 2) + (layout.height / 2)), + bottom_screen_width, bottom_screen_height / 2, orientation); + break; + } case Settings::StereoRenderOption::CardboardVR: { DrawSingleScreen(screen_infos[2], bottom_screen_left, bottom_screen_top, bottom_screen_width, bottom_screen_height, orientation);