Viewport scaling and display density independence

The view is scaled to be as large as possible, without changing the aspect, within the bounds of the window.
On "retina" displays, or other displays where window units != pixels, the view should no longer draw incorrectly.
This commit is contained in:
Kevin Hartman 2014-08-29 22:23:12 -07:00 committed by Tony Wasserka
parent c8d933a142
commit 221a9b023d
7 changed files with 89 additions and 4 deletions

View file

@ -191,7 +191,8 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x
* Draws the emulated screens to the emulator window.
*/
void RendererOpenGL::DrawScreens() {
glViewport(0, 0, resolution_width, resolution_height);
UpdateViewportExtent();
glViewport(viewport_extent.x, viewport_extent.y, viewport_extent.width, viewport_extent.height);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program_id);
@ -228,6 +229,39 @@ void RendererOpenGL::SetWindow(EmuWindow* window) {
render_window = window;
}
void RendererOpenGL::UpdateViewportExtent() {
int width_in_pixels;
int height_in_pixels;
render_window->GetFramebufferSize(&width_in_pixels, &height_in_pixels);
// No update needed if framebuffer size hasn't changed
if (width_in_pixels == framebuffer_size.width && height_in_pixels == framebuffer_size.height) {
return;
}
framebuffer_size.width = width_in_pixels;
framebuffer_size.height = height_in_pixels;
float window_aspect_ratio = static_cast<float>(height_in_pixels) / width_in_pixels;
float emulation_aspect_ratio = static_cast<float>(resolution_height) / resolution_width;
if (window_aspect_ratio > emulation_aspect_ratio) {
// If the window is more narrow than the emulation content, borders are applied on the
// top and bottom of the window.
viewport_extent.width = width_in_pixels;
viewport_extent.height = emulation_aspect_ratio * viewport_extent.width;
viewport_extent.x = 0;
viewport_extent.y = (height_in_pixels - viewport_extent.height) / 2;
} else {
// Otherwise, borders are applied on the left and right sides of the window.
viewport_extent.height = height_in_pixels;
viewport_extent.width = (1 / emulation_aspect_ratio) * viewport_extent.height;
viewport_extent.x = (width_in_pixels - viewport_extent.width) / 2;
viewport_extent.y = 0;
}
}
/// Initialize the renderer
void RendererOpenGL::Init() {
render_window->MakeCurrent();

View file

@ -52,12 +52,27 @@ private:
static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
const TextureInfo& texture);
/// Updates the viewport rectangle
void UpdateViewportExtent();
EmuWindow* render_window; ///< Handle to render window
u32 last_mode; ///< Last render mode
int resolution_width; ///< Current resolution width
int resolution_height; ///< Current resolution height
struct {
int width;
int height;
} framebuffer_size; ///< Current framebuffer size
struct {
int x;
int y;
int width;
int height;
} viewport_extent; ///< Current viewport rectangle
// OpenGL object IDs
GLuint vertex_array_handle;
GLuint vertex_buffer_handle;