diff --git a/src/citra/config.cpp b/src/citra/config.cpp index ce51b687b..c296e062e 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -108,6 +108,10 @@ void Config::ReadValues() { Settings::values.frame_limit = static_cast(sdl2_config->GetInteger("Renderer", "frame_limit", 100)); + Settings::values.toggle_3d = sdl2_config->GetBoolean("Renderer", "toggle_3d", false); + Settings::values.factor_3d = + static_cast(sdl2_config->GetInteger("Renderer", "factor_3d", 0)); + Settings::values.bg_red = (float)sdl2_config->GetReal("Renderer", "bg_red", 0.0); Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0); Settings::values.bg_blue = (float)sdl2_config->GetReal("Renderer", "bg_blue", 0.0); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 4a17eb6ca..c501a6de7 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -116,6 +116,14 @@ bg_red = bg_blue = bg_green = +# Toggles Stereoscopic 3D +# 0 (default): Off, 1: On +toggle_3d = + +# Change 3D Intensity +# 0 - 100: Intensity. 0 (default) +factor_3d = + [Layout] # Layout for the screen inside the render window. # 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen, 3: Side by Side diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index ce80a727d..8d9561353 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -100,6 +100,8 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Layout"); + Settings::values.toggle_3d = qt_config->value("toggle_3d", false).toBool(); + Settings::values.factor_3d = qt_config->value("factor_3d", 0).toInt(); Settings::values.layout_option = static_cast(qt_config->value("layout_option").toInt()); Settings::values.swap_screen = qt_config->value("swap_screen", false).toBool(); @@ -323,6 +325,8 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Layout"); + qt_config->setValue("toggle_3d", Settings::values.toggle_3d); + qt_config->setValue("factor_3d", Settings::values.factor_3d); qt_config->setValue("layout_option", static_cast(Settings::values.layout_option)); qt_config->setValue("swap_screen", Settings::values.swap_screen); qt_config->setValue("custom_layout", Settings::values.custom_layout); diff --git a/src/citra_qt/configuration/configure_graphics.cpp b/src/citra_qt/configuration/configure_graphics.cpp index f167d3742..7868702f5 100644 --- a/src/citra_qt/configuration/configure_graphics.cpp +++ b/src/citra_qt/configuration/configure_graphics.cpp @@ -40,6 +40,8 @@ void ConfigureGraphics::setConfiguration() { ui->toggle_vsync->setChecked(Settings::values.use_vsync); ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); ui->frame_limit->setValue(Settings::values.frame_limit); + ui->factor_3d->setValue(Settings::values.factor_3d); + ui->toggle_3d->setChecked(Settings::values.toggle_3d); ui->layout_combobox->setCurrentIndex(static_cast(Settings::values.layout_option)); ui->swap_screen->setChecked(Settings::values.swap_screen); } @@ -55,6 +57,8 @@ void ConfigureGraphics::applyConfiguration() { Settings::values.use_vsync = ui->toggle_vsync->isChecked(); Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); Settings::values.frame_limit = ui->frame_limit->value(); + Settings::values.factor_3d = ui->factor_3d->value(); + Settings::values.toggle_3d = ui->toggle_3d->isChecked(); Settings::values.layout_option = static_cast(ui->layout_combobox->currentIndex()); Settings::values.swap_screen = ui->swap_screen->isChecked(); diff --git a/src/citra_qt/configuration/configure_graphics.ui b/src/citra_qt/configuration/configure_graphics.ui index 330a5fb82..9ba4bd0b1 100644 --- a/src/citra_qt/configuration/configure_graphics.ui +++ b/src/citra_qt/configuration/configure_graphics.ui @@ -228,6 +228,33 @@ Layout + + + + + + Enable Stereoscopic 3D + + + + + + + % + + + 0 + + + 100 + + + 0 + + + + + diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index e67394177..5aa98238e 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -60,9 +60,17 @@ EmuWindow::~EmuWindow() { */ static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigned framebuffer_x, unsigned framebuffer_y) { - return ( - framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom && - framebuffer_x >= layout.bottom_screen.left && framebuffer_x < layout.bottom_screen.right); + if (Settings::values.toggle_3d) { + return (framebuffer_y >= layout.bottom_screen.top && + framebuffer_y < layout.bottom_screen.bottom && + framebuffer_x >= layout.bottom_screen.left / 2 && + framebuffer_x < layout.bottom_screen.right / 2); + } else { + return (framebuffer_y >= layout.bottom_screen.top && + framebuffer_y < layout.bottom_screen.bottom && + framebuffer_x >= layout.bottom_screen.left && + framebuffer_x < layout.bottom_screen.right); + } } std::tuple EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { @@ -80,9 +88,16 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { return; std::lock_guard guard(touch_state->mutex); - touch_state->touch_x = - static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left) / - (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); + if (Settings::values.toggle_3d) { + touch_state->touch_x = + static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left / 2) / + (framebuffer_layout.bottom_screen.right / 2 - + framebuffer_layout.bottom_screen.left / 2); + } else { + touch_state->touch_x = + 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); diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 8a8a32d51..730f0271f 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp @@ -8,6 +8,7 @@ #include "core/core_timing.h" #include "core/hle/service/ptm/ptm.h" #include "core/hle/shared_page.h" +#include "core/settings.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -83,6 +84,10 @@ void Init() { update_time_event = CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback); CoreTiming::ScheduleEvent(0, update_time_event); + + float slidestate = + Settings::values.toggle_3d ? (float_le)Settings::values.factor_3d / 100 : 0.0f; + shared_page.sliderstate_3d = slidestate; } void SetMacAddress(const MacAddress& addr) { diff --git a/src/core/settings.h b/src/core/settings.h index 5ce4811af..af56e5599 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -132,6 +132,9 @@ struct Values { float bg_green; float bg_blue; + bool toggle_3d; + u8 factor_3d; + // Audio std::string sink_id; bool enable_audio_stretching; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 65c18aecc..625a3755b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -103,12 +103,13 @@ void RendererOpenGL::SwapBuffers() { OpenGLState prev_state = OpenGLState::GetCurState(); state.Apply(); - for (int i : {0, 1}) { - const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; + for (int i : {0, 1, 2}) { + int fb_id = i == 2 ? 1 : 0; + const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id]; // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04 u32 lcd_color_addr = - (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); + (fb_id == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom); lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr; LCD::Regs::ColorFill color_fill = {0}; LCD::Read(color_fill.raw, lcd_color_addr); @@ -129,7 +130,7 @@ void RendererOpenGL::SwapBuffers() { // performance problem. ConfigureFramebufferTexture(screen_infos[i].texture, framebuffer); } - LoadFBToScreenInfo(framebuffer, screen_infos[i]); + LoadFBToScreenInfo(framebuffer, screen_infos[i], i == 1); // Resize the texture in case the framebuffer size has changed screen_infos[i].texture.width = framebuffer.width; @@ -160,10 +161,15 @@ void RendererOpenGL::SwapBuffers() { * Loads framebuffer from emulated memory into the active OpenGL texture. */ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, - ScreenInfo& screen_info) { + ScreenInfo& screen_info, bool right_eye) { + + if (framebuffer.address_right1 == 0 || framebuffer.address_right2 == 0) + right_eye = false; const PAddr framebuffer_addr = - framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2; + framebuffer.active_fb == 0 + ? (!right_eye ? framebuffer.address_left1 : framebuffer.address_right1) + : (!right_eye ? framebuffer.address_left2 : framebuffer.address_right2); LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", framebuffer.stride * framebuffer.height, framebuffer_addr, (int)framebuffer.width, @@ -395,13 +401,33 @@ void RendererOpenGL::DrawScreens() { glUniform1i(uniform_color_texture, 0); if (layout.top_screen_enabled) { - DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, (float)top_screen.top, - (float)top_screen.GetWidth(), (float)top_screen.GetHeight()); + if (!Settings::values.toggle_3d) { + DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, (float)top_screen.top, + (float)top_screen.GetWidth(), (float)top_screen.GetHeight()); + } else { + DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2, + (float)top_screen.top, (float)top_screen.GetWidth() / 2, + (float)top_screen.GetHeight()); + DrawSingleScreenRotated(screen_infos[1], + ((float)top_screen.left / 2) + ((float)layout.width / 2), + (float)top_screen.top, (float)top_screen.GetWidth() / 2, + (float)top_screen.GetHeight()); + } } if (layout.bottom_screen_enabled) { - DrawSingleScreenRotated(screen_infos[1], (float)bottom_screen.left, - (float)bottom_screen.top, (float)bottom_screen.GetWidth(), - (float)bottom_screen.GetHeight()); + if (!Settings::values.toggle_3d) { + DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left, + (float)bottom_screen.top, (float)bottom_screen.GetWidth(), + (float)bottom_screen.GetHeight()); + } else { + DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left / 2, + (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, + (float)bottom_screen.GetHeight()); + DrawSingleScreenRotated(screen_infos[2], + ((float)bottom_screen.left / 2) + ((float)layout.width / 2), + (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, + (float)bottom_screen.GetHeight()); + } } m_current_frame++; diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index f827a26af..991e9475f 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -62,7 +62,7 @@ private: // Loads framebuffer from emulated memory into the display information structure void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, - ScreenInfo& screen_info); + ScreenInfo& screen_info, bool right_eye); // Fills active OpenGL texture with the given RGB color. void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture); @@ -76,7 +76,7 @@ private: OGLProgram shader; /// Display information for top and bottom screens respectively - std::array screen_infos; + std::array screen_infos; // Shader uniform location indices GLuint uniform_modelview_matrix;