diff --git a/src/window/gui/Gui.cpp b/src/window/gui/Gui.cpp index b972f6c03..769528fb3 100644 --- a/src/window/gui/Gui.cpp +++ b/src/window/gui/Gui.cpp @@ -384,13 +384,18 @@ void Gui::DrawMenu() { gfx_current_game_window_viewport.width = (int16_t)size.x; gfx_current_game_window_viewport.height = (int16_t)size.y; + if (CVarGetInteger("gAdvancedResolution.Enabled", 0)) { + ApplyResolutionChanges(); + } + switch (CVarGetInteger("gLowResMode", 0)) { case 1: { // N64 Mode gfx_current_dimensions.width = 320; gfx_current_dimensions.height = 240; + /* const int sw = size.y * 320 / 240; gfx_current_game_window_viewport.x += ((int)size.x - sw) / 2; - gfx_current_game_window_viewport.width = sw; + gfx_current_game_window_viewport.width = sw;*/ break; } case 2: { // 240p Widescreen @@ -459,14 +464,93 @@ void Gui::ImGuiWMNewFrame() { } } +void Gui::ApplyResolutionChanges() { + ImVec2 size = ImGui::GetContentRegionAvail(); + + const float aspectRatioX = CVarGetFloat("gAdvancedResolution.AspectRatioX", 16.0f); + const float aspectRatioY = CVarGetFloat("gAdvancedResolution.AspectRatioY", 9.0f); + const uint32_t verticalPixelCount = CVarGetInteger("gAdvancedResolution.VerticalPixelCount", 480); + const bool verticalResolutionToggle = CVarGetInteger("gAdvancedResolution.VerticalResolutionToggle", 0); + + const bool aspectRatioIsEnabled = (aspectRatioX > 0.0f) && (aspectRatioY > 0.0f); + + const uint32_t minResolutionWidth = 320; + const uint32_t minResolutionHeight = 240; + const uint32_t maxResolutionWidth = 8096; // the renderer's actual limit is 16384 + const uint32_t maxResolutionHeight = 4320; // on either axis. if you have the VRAM for it. + uint32_t newWidth = gfx_current_dimensions.width; + uint32_t newHeight = gfx_current_dimensions.height; + + if (verticalResolutionToggle) { // Use fixed vertical resolution + if (aspectRatioIsEnabled) { + newWidth = uint32_t(float(verticalPixelCount / aspectRatioY) * aspectRatioX); + } else { + newWidth = uint32_t(float(verticalPixelCount * size.x / size.y)); + } + newHeight = verticalPixelCount; + } else { // Use the window's resolution + if (aspectRatioIsEnabled) { + if (((float)gfx_current_game_window_viewport.width / gfx_current_game_window_viewport.height) > + (aspectRatioX / aspectRatioY)) { + // when pillarboxed + newWidth = uint32_t(float(gfx_current_dimensions.height / aspectRatioY) * aspectRatioX); + } else { // when letterboxed + newHeight = uint32_t(float(gfx_current_dimensions.width / aspectRatioX) * aspectRatioY); + } + } // else, having both options turned off does nothing. + } + // clamp values to prevent renderer crash + if (newWidth < minResolutionWidth) { + newWidth = minResolutionWidth; + } + if (newHeight < minResolutionHeight) { + newHeight = minResolutionHeight; + } + if (newWidth > maxResolutionWidth) { + newWidth = maxResolutionWidth; + } + if (newHeight > maxResolutionHeight) { + newHeight = maxResolutionHeight; + } + // apply new dimensions + gfx_current_dimensions.width = newWidth; + gfx_current_dimensions.height = newHeight; + // centring the image is done in Gui::StartFrame(). +} + void Gui::StartFrame() { const ImVec2 mainPos = ImGui::GetWindowPos(); ImVec2 size = ImGui::GetContentRegionAvail(); ImVec2 pos = ImVec2(0, 0); - if (CVarGetInteger("gLowResMode", 0) == 1) { + if (CVarGetInteger("gLowResMode", 0) == 1) { // N64 Mode takes priority const float sw = size.y * 320.0f / 240.0f; pos = ImVec2(size.x / 2 - sw / 2, 0); size = ImVec2(sw, size.y); + } else if (CVarGetInteger("gAdvancedResolution.Enabled", 0)) { + if (!CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0)) { + if (!CVarGetInteger("gAdvancedResolution.IgnoreAspectCorrection", 0)) { + float sWdth = size.y * gfx_current_dimensions.width / gfx_current_dimensions.height; + float sHght = size.x * gfx_current_dimensions.height / gfx_current_dimensions.width; + float sPosX = size.x / 2 - sWdth / 2; + float sPosY = size.y / 2 - sHght / 2; + if (sPosY < 0.0f) { // pillarbox + sPosY = 0.0f; // clamp y position + sHght = size.y; // reset height + } + if (sPosX < 0.0f) { // letterbox + sPosX = 0.0f; // clamp x position + sWdth = size.x; // reset width + } + pos = ImVec2(sPosX, sPosY); + size = ImVec2(sWdth, sHght); + } + } else { // in pixel perfect mode it's much easier + const int factor = CVarGetInteger("gAdvancedResolution.IntegerScaleFactor", 1); + float sPosX = size.x / 2 - (gfx_current_dimensions.width * factor) / 2; + float sPosY = size.y / 2 - (gfx_current_dimensions.height * factor) / 2; + pos = ImVec2(sPosX, sPosY); + size = ImVec2(float(gfx_current_dimensions.width) * factor, float(gfx_current_dimensions.height) * factor); + } } if (gfxFramebuffer) { ImGui::SetCursorPos(pos); diff --git a/src/window/gui/Gui.h b/src/window/gui/Gui.h index 2ffb6a05b..b163e9e43 100644 --- a/src/window/gui/Gui.h +++ b/src/window/gui/Gui.h @@ -90,6 +90,7 @@ class Gui { void ImGuiWMNewFrame(); void ImGuiRenderDrawData(ImDrawData* data); ImTextureID GetTextureById(int32_t id); + void ApplyResolutionChanges(); private: struct GuiTexture {