From 9960c49c217d2c1ae202bdacd475c9a47cda39b9 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sat, 7 Mar 2015 17:21:19 -0500
Subject: [PATCH] Set framebuffer layout from EmuWindow.

---
 src/citra/emu_window/emu_window_glfw.cpp      | 11 +---
 src/citra_qt/bootmanager.cpp                  |  3 +-
 src/common/emu_window.cpp                     | 50 +++++++++++++++++++
 src/common/emu_window.h                       | 32 +++++++++---
 .../renderer_opengl/renderer_opengl.cpp       | 48 ++++--------------
 src/video_core/video_core.cpp                 |  3 --
 src/video_core/video_core.h                   |  1 -
 7 files changed, 88 insertions(+), 60 deletions(-)

diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index ec3e8cf34..81231e1e5 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -36,20 +36,13 @@ const bool EmuWindow_GLFW::IsOpen() {
 }
 
 void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) {
-    ASSERT(width > 0);
-    ASSERT(height > 0);
-
-    GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height));
+    GetEmuWindow(win)->NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, height));
 }
 
 void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) {
-    ASSERT(width > 0);
-    ASSERT(height > 0);
-
     // NOTE: GLFW provides no proper way to set a minimal window size.
     //       Hence, we just ignore the corresponding EmuWindow hint.
-
-    GetEmuWindow(win)->NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(width, height));
+    OnFramebufferResizeEvent(win, width, height);
 }
 
 /// EmuWindow_GLFW constructor
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 6514288a0..a040e75c1 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -155,6 +155,7 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this
 
     child = new GGLWidgetInternal(fmt, this);
     QBoxLayout* layout = new QHBoxLayout(this);
+
     resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
     layout->addWidget(child);
     layout->setMargin(0);
@@ -234,7 +235,7 @@ void GRenderWindow::OnFramebufferSizeChanged()
     unsigned height = child->QPaintDevice::height();
 #endif
 
-    NotifyFramebufferSizeChanged(std::make_pair(width, height));
+    NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, height));
 }
 
 void GRenderWindow::BackupGeometry()
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 48bb35db5..1082ae26d 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "emu_window.h"
+#include "video_core/video_core.h"
 
 void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) {
     Service::HID::PadState mapped_key = KeyMap::GetPadKey(key);
@@ -15,3 +16,52 @@ void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) {
 
     Service::HID::PadButtonRelease(mapped_key);
 }
+
+EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(int width, int height) {
+    ASSERT(width > 0);
+    ASSERT(height > 0);
+
+    EmuWindow::FramebufferLayout res = { width, height, {}, {} };
+
+    float window_aspect_ratio = static_cast<float>(height) / width;
+    float emulation_aspect_ratio = static_cast<float>(VideoCore::kScreenTopHeight * 2) /
+        VideoCore::kScreenTopWidth;
+
+    if (window_aspect_ratio > emulation_aspect_ratio) {
+        // Window is narrower than the emulation content => apply borders to the top and bottom
+        int viewport_height = static_cast<int>(std::round(emulation_aspect_ratio * width));
+
+        res.top_screen.left = 0;
+        res.top_screen.right = res.top_screen.left + width;
+        res.top_screen.top = (height - viewport_height) / 2;
+        res.top_screen.bottom = res.top_screen.top + viewport_height / 2;
+
+        int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) /
+            VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left));
+        int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
+
+        res.bottom_screen.left = bottom_border;
+        res.bottom_screen.right = res.bottom_screen.left + bottom_width;
+        res.bottom_screen.top = res.top_screen.bottom;
+        res.bottom_screen.bottom = res.bottom_screen.top + viewport_height / 2;
+    } else {
+        // Otherwise, apply borders to the left and right sides of the window.
+        int viewport_width = static_cast<int>(std::round(height / emulation_aspect_ratio));
+
+        res.top_screen.left = (width - viewport_width) / 2;
+        res.top_screen.right = res.top_screen.left + viewport_width;
+        res.top_screen.top = 0;
+        res.top_screen.bottom = res.top_screen.top + height / 2;
+
+        int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) /
+            VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left));
+        int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
+
+        res.bottom_screen.left = res.top_screen.left + bottom_border;
+        res.bottom_screen.right = res.bottom_screen.left + bottom_width;
+        res.bottom_screen.top = res.top_screen.bottom;
+        res.bottom_screen.bottom = res.bottom_screen.top + height / 2;
+    }
+
+    return res;
+}
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 1ad4b82a3..b6862030e 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -8,6 +8,7 @@
 #include "common/scm_rev.h"
 #include "common/string_util.h"
 #include "common/key_map.h"
+#include "common/math_util.h"
 
 /**
  * Abstraction class used to provide an interface between emulation code and the frontend
@@ -38,6 +39,23 @@ public:
         std::pair<unsigned,unsigned> min_client_area_size;
     };
 
+    /// Describes the layout of the window framebuffer (size and top/bottom screen positions)
+    struct FramebufferLayout {
+
+        /**
+         * Factory method for constructing a default FramebufferLayout
+         * @param width Window framebuffer width in pixels
+         * @param height Window framebuffer height in pixels
+         * @return Newly created FramebufferLayout object with default screen regions initialized
+         */
+        static FramebufferLayout DefaultScreenLayout(int width, int height);
+
+        unsigned width;
+        unsigned height;
+        MathUtil::Rectangle<unsigned> top_screen;
+        MathUtil::Rectangle<unsigned> bottom_screen;
+    };
+
     /// Swap buffers to display the next frame
     virtual void SwapBuffers() = 0;
 
@@ -75,11 +93,11 @@ public:
     }
 
     /**
-      * Gets the framebuffer size in pixels.
+      * Gets the framebuffer layout (width, height, and screen regions)
       * @note This method is thread-safe
       */
-    const std::pair<unsigned,unsigned> GetFramebufferSize() const {
-        return framebuffer_size;
+    const FramebufferLayout& GetFramebufferLayout() const {
+        return framebuffer_layout;
     }
 
     /**
@@ -118,11 +136,11 @@ protected:
     }
 
     /**
-     * Update internal framebuffer size with the given parameter.
+     * Update framebuffer layout with the given parameter.
      * @note EmuWindow implementations will usually use this in window resize event handlers.
      */
-    void NotifyFramebufferSizeChanged(const std::pair<unsigned,unsigned>& size) {
-        framebuffer_size = size;
+    void NotifyFramebufferLayoutChanged(const FramebufferLayout& layout) {
+        framebuffer_layout = layout;
     }
 
     /**
@@ -143,7 +161,7 @@ private:
         // By default, ignore this request and do nothing.
     }
 
-    std::pair<unsigned,unsigned> framebuffer_size;
+    FramebufferLayout framebuffer_layout; ///< Current framebuffer layout
 
     unsigned client_area_width;    ///< Current client width, should be set by window impl.
     unsigned client_area_height;   ///< Current client height, should be set by window impl.
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 272695174..fc8af9d40 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -242,28 +242,26 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x
  * Draws the emulated screens to the emulator window.
  */
 void RendererOpenGL::DrawScreens() {
-    auto viewport_extent = GetViewportExtent();
-    glViewport(viewport_extent.left, viewport_extent.top, viewport_extent.GetWidth(), viewport_extent.GetHeight()); // TODO: Or bottom?
+    auto layout = render_window->GetFramebufferLayout();
+
+    glViewport(0, 0, layout.width, layout.height);
     glClear(GL_COLOR_BUFFER_BIT);
 
     glUseProgram(program_id);
 
     // Set projection matrix
-    std::array<GLfloat, 3*2> ortho_matrix = MakeOrthographicMatrix((float)resolution_width, (float)resolution_height);
+    std::array<GLfloat, 3 * 2> ortho_matrix = MakeOrthographicMatrix((float)layout.width,
+        (float)layout.height);
     glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
 
     // Bind texture in Texture Unit 0
     glActiveTexture(GL_TEXTURE0);
     glUniform1i(uniform_color_texture, 0);
 
-    const float max_width = std::max((float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenBottomWidth);
-    const float top_x = 0.5f * (max_width - VideoCore::kScreenTopWidth);
-    const float bottom_x = 0.5f * (max_width - VideoCore::kScreenBottomWidth);
-
-    DrawSingleScreenRotated(textures[0], top_x, 0,
-        (float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenTopHeight);
-    DrawSingleScreenRotated(textures[1], bottom_x, (float)VideoCore::kScreenTopHeight,
-        (float)VideoCore::kScreenBottomWidth, (float)VideoCore::kScreenBottomHeight);
+    DrawSingleScreenRotated(textures[0], (float)layout.top_screen.left, (float)layout.top_screen.top,
+        (float)layout.top_screen.GetWidth(), (float)layout.top_screen.GetHeight());
+    DrawSingleScreenRotated(textures[1], (float)layout.bottom_screen.left,(float)layout.bottom_screen.top,
+        (float)layout.bottom_screen.GetWidth(), (float)layout.bottom_screen.GetHeight());
 
     m_current_frame++;
 }
@@ -280,34 +278,6 @@ void RendererOpenGL::SetWindow(EmuWindow* window) {
     render_window = window;
 }
 
-MathUtil::Rectangle<unsigned> RendererOpenGL::GetViewportExtent() {
-    unsigned framebuffer_width;
-    unsigned framebuffer_height;
-    std::tie(framebuffer_width, framebuffer_height) = render_window->GetFramebufferSize();
-
-    float window_aspect_ratio = static_cast<float>(framebuffer_height) / framebuffer_width;
-    float emulation_aspect_ratio = static_cast<float>(resolution_height) / resolution_width;
-
-    MathUtil::Rectangle<unsigned> viewport_extent;
-    if (window_aspect_ratio > emulation_aspect_ratio) {
-        // Window is narrower than the emulation content => apply borders to the top and bottom
-        unsigned viewport_height = static_cast<unsigned>(std::round(emulation_aspect_ratio * framebuffer_width));
-        viewport_extent.left = 0;
-        viewport_extent.top = (framebuffer_height - viewport_height) / 2;
-        viewport_extent.right = viewport_extent.left + framebuffer_width;
-        viewport_extent.bottom = viewport_extent.top + viewport_height;
-    } else {
-        // Otherwise, apply borders to the left and right sides of the window.
-        unsigned viewport_width = static_cast<unsigned>(std::round(framebuffer_height / emulation_aspect_ratio));
-        viewport_extent.left = (framebuffer_width - viewport_width) / 2;
-        viewport_extent.top = 0;
-        viewport_extent.right = viewport_extent.left + viewport_width;
-        viewport_extent.bottom = viewport_extent.top + framebuffer_height;
-    }
-
-    return viewport_extent;
-}
-
 /// Initialize the renderer
 void RendererOpenGL::Init() {
     render_window->MakeCurrent();
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 0a236595c..b9d4ede3a 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -18,7 +18,6 @@ namespace VideoCore {
 
 EmuWindow*      g_emu_window    = nullptr;     ///< Frontend emulator window
 RendererBase*   g_renderer      = nullptr;     ///< Renderer plugin
-int             g_current_frame = 0;
 
 /// Initialize the video core
 void Init(EmuWindow* emu_window) {
@@ -27,8 +26,6 @@ void Init(EmuWindow* emu_window) {
     g_renderer->SetWindow(g_emu_window);
     g_renderer->Init();
 
-    g_current_frame = 0;
-
     LOG_DEBUG(Render, "initialized OK");
 }
 
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index b782f17bd..1b51d39bf 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -30,7 +30,6 @@ static const int kScreenBottomHeight    = 240;  ///< 3DS bottom screen height
 // ---------------------
 
 extern RendererBase*   g_renderer;              ///< Renderer plugin
-extern int             g_current_frame;         ///< Current frame
 extern EmuWindow*      g_emu_window;            ///< Emu window
 
 /// Start the video core