diff --git a/android/app/src/main/res/values-es/arrays.xml b/android/app/src/main/res/values-es/arrays.xml index 746d5e9d2..4ae8d947e 100644 --- a/android/app/src/main/res/values-es/arrays.xml +++ b/android/app/src/main/res/values-es/arrays.xml @@ -45,6 +45,7 @@ Auto (Nativo del juego) + Auto (Match Display) 4:3 16:9 16:10 diff --git a/android/app/src/main/res/values-it/arrays.xml b/android/app/src/main/res/values-it/arrays.xml index c12144117..ace19f3c9 100644 --- a/android/app/src/main/res/values-it/arrays.xml +++ b/android/app/src/main/res/values-it/arrays.xml @@ -45,6 +45,7 @@ Auto (Game Native) + Auto (Match Display) 4:3 16:9 16:10 diff --git a/android/app/src/main/res/values-nl/arrays.xml b/android/app/src/main/res/values-nl/arrays.xml index c1e3e4aa4..2ff0056a1 100644 --- a/android/app/src/main/res/values-nl/arrays.xml +++ b/android/app/src/main/res/values-nl/arrays.xml @@ -45,6 +45,7 @@ Auto (Game Native) + Auto (Match Display) 4:3 16:9 16:10 diff --git a/android/app/src/main/res/values-pt-rBR/arrays.xml b/android/app/src/main/res/values-pt-rBR/arrays.xml index 7e73bb9e3..678cc19d1 100644 --- a/android/app/src/main/res/values-pt-rBR/arrays.xml +++ b/android/app/src/main/res/values-pt-rBR/arrays.xml @@ -45,6 +45,7 @@ Auto (Nativo) + Auto (Match Display) 4:3 16:9 16:10 diff --git a/android/app/src/main/res/values-ru/arrays.xml b/android/app/src/main/res/values-ru/arrays.xml index 914e01cfd..7745642d6 100644 --- a/android/app/src/main/res/values-ru/arrays.xml +++ b/android/app/src/main/res/values-ru/arrays.xml @@ -44,8 +44,9 @@ Все границы - Автонастройка (нативное игре) - 4:3 + Автонастройка (нативное игре) + Auto (Match Display) + 4:3 16:9 16:10 19:9 diff --git a/android/app/src/main/res/values/arrays.xml b/android/app/src/main/res/values/arrays.xml index f325f0be3..82e703dcd 100644 --- a/android/app/src/main/res/values/arrays.xml +++ b/android/app/src/main/res/values/arrays.xml @@ -89,6 +89,7 @@ Auto (Game Native) + Auto (Match Display) 4:3 16:9 16:10 @@ -105,6 +106,7 @@ Auto (Game Native) + Auto (Match Window) 4:3 16:9 16:10 diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index ed086e83e..a5a1b90fa 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -492,7 +492,7 @@ float GPU::GetDisplayAspectRatio() const } else { - return Settings::GetDisplayAspectRatioValue(g_settings.display_aspect_ratio); + return g_settings.GetDisplayAspectRatioValue(); } } diff --git a/src/core/gte.cpp b/src/core/gte.cpp index 53b78710b..71a492385 100644 --- a/src/core/gte.cpp +++ b/src/core/gte.cpp @@ -3,10 +3,13 @@ #include "common/bitutils.h" #include "common/state_wrapper.h" #include "cpu_core.h" +#include "host_display.h" +#include "host_interface.h" #include "pgxp.h" #include "settings.h" #include #include +#include namespace GTE { @@ -19,6 +22,11 @@ static constexpr s32 IR0_MAX_VALUE = 0x1000; static constexpr s32 IR123_MIN_VALUE = -(INT64_C(1) << 15); static constexpr s32 IR123_MAX_VALUE = (INT64_C(1) << 15) - 1; +static DisplayAspectRatio s_aspect_ratio = DisplayAspectRatio::R4_3; +static u32 s_custom_aspect_ratio_numerator; +static u32 s_custom_aspect_ratio_denominator; +static float s_custom_aspect_ratio_f; + #define REGS CPU::g_state.gte_regs ALWAYS_INLINE static u32 CountLeadingBits(u32 value) @@ -148,6 +156,7 @@ ALWAYS_INLINE static u32 TruncateRGB(s32 value) void Initialize() { + UpdateAspectRatio(); Reset(); } @@ -162,6 +171,55 @@ bool DoState(StateWrapper& sw) return !sw.HasError(); } +void UpdateAspectRatio() +{ + if (!g_settings.gpu_widescreen_hack) + { + s_aspect_ratio = DisplayAspectRatio::R4_3; + return; + } + + s_aspect_ratio = g_settings.display_aspect_ratio; + + u32 num, denom; + switch (s_aspect_ratio) + { + case DisplayAspectRatio::MatchWindow: + { + const HostDisplay* display = g_host_interface->GetDisplay(); + if (!display) + { + s_aspect_ratio = DisplayAspectRatio::R4_3; + return; + } + + num = display->GetWindowWidth(); + denom = display->GetWindowHeight(); + } + break; + + case DisplayAspectRatio::Custom: + { + num = g_settings.display_aspect_ratio_custom_numerator; + denom = g_settings.display_aspect_ratio_custom_denominator; + } + break; + + default: + return; + } + + // (4 / 3) / (num / denom) => gcd((4 * denom) / (3 * num)) + const u32 x = 4u * denom; + const u32 y = 3u * num; + const u32 gcd = std::gcd(x, y); + + s_custom_aspect_ratio_numerator = x / gcd; + s_custom_aspect_ratio_denominator = y / gcd; + + s_custom_aspect_ratio_f = static_cast((4.0 / 3.0) / (static_cast(num) / static_cast(denom))); +} + u32 ReadRegister(u32 index) { DebugAssert(index < countof(REGS.r32)); @@ -614,66 +672,65 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last) const s64 result = static_cast(ZeroExtend64(UNRDivide(REGS.H, REGS.SZ3))); s64 Sx; - if (g_settings.gpu_widescreen_hack) + switch (s_aspect_ratio) { - const DisplayAspectRatio ar = g_settings.display_aspect_ratio; - switch (ar) - { - case DisplayAspectRatio::R16_9: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(4)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R16_9: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(4)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R16_10: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(5)) / s64(6)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R16_10: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(5)) / s64(6)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R19_9: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(12)) / s64(19)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R19_9: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(12)) / s64(19)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R20_9: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(5)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R20_9: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(5)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R21_9: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(9)) / s64(16)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R21_9: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(9)) / s64(16)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R32_9: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(8)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R32_9: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(8)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R8_7: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R8_7: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R5_4: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(16)) / s64(15)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R5_4: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(16)) / s64(15)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R3_2: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(8)) / s64(9)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R3_2: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(8)) / s64(9)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R2_1: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(2)) / s64(3)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R2_1: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(2)) / s64(3)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::R1_1: - Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX)); - break; + case DisplayAspectRatio::R1_1: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX)); + break; - case DisplayAspectRatio::Auto: - case DisplayAspectRatio::R4_3: - case DisplayAspectRatio::PAR1_1: - default: - Sx = (s64(result) * s64(REGS.IR1) + s64(REGS.OFX)); - break; - } - } - else - { - Sx = (s64(result) * s64(REGS.IR1) + s64(REGS.OFX)); + case DisplayAspectRatio::Custom: + case DisplayAspectRatio::MatchWindow: + Sx = ((((s64(result) * s64(REGS.IR1)) * s64(s_custom_aspect_ratio_numerator)) / + s64(s_custom_aspect_ratio_denominator)) + + s64(REGS.OFX)); + break; + + case DisplayAspectRatio::Auto: + case DisplayAspectRatio::R4_3: + case DisplayAspectRatio::PAR1_1: + default: + Sx = (s64(result) * s64(REGS.IR1) + s64(REGS.OFX)); + break; } const s64 Sy = s64(result) * s64(REGS.IR2) + s64(REGS.OFY); @@ -713,70 +770,68 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last) const float precise_h_div_sz = float(REGS.H) / precise_z; const float fofx = float(REGS.OFX) / float(1 << 16); const float fofy = float(REGS.OFY) / float(1 << 16); - float precise_x; - if (g_settings.gpu_widescreen_hack) + float precise_x = precise_ir1 * precise_h_div_sz; + + switch (s_aspect_ratio) { - precise_x = precise_ir1 * precise_h_div_sz; - const DisplayAspectRatio ar = g_settings.display_aspect_ratio; - switch (ar) - { - case DisplayAspectRatio::R16_9: - precise_x = (precise_x * 3.0f) / 4.0f; - break; + case DisplayAspectRatio::R16_9: + precise_x = (precise_x * 3.0f) / 4.0f; + break; - case DisplayAspectRatio::R16_10: - precise_x = (precise_x * 5.0f) / 6.0f; - break; + case DisplayAspectRatio::R16_10: + precise_x = (precise_x * 5.0f) / 6.0f; + break; - case DisplayAspectRatio::R19_9: - precise_x = (precise_x * 12.0f) / 19.0f; - break; + case DisplayAspectRatio::R19_9: + precise_x = (precise_x * 12.0f) / 19.0f; + break; - case DisplayAspectRatio::R20_9: - precise_x = (precise_x * 3.0f) / 5.0f; - break; + case DisplayAspectRatio::R20_9: + precise_x = (precise_x * 3.0f) / 5.0f; + break; - case DisplayAspectRatio::R21_9: - precise_x = (precise_x * 9.0f) / 16.0f; - break; + case DisplayAspectRatio::R21_9: + precise_x = (precise_x * 9.0f) / 16.0f; + break; - case DisplayAspectRatio::R32_9: - precise_x = (precise_x * 3.0f) / 8.0f; - break; + case DisplayAspectRatio::R32_9: + precise_x = (precise_x * 3.0f) / 8.0f; + break; - case DisplayAspectRatio::R8_7: - precise_x = (precise_x * 7.0f) / 6.0f; - break; + case DisplayAspectRatio::R8_7: + precise_x = (precise_x * 7.0f) / 6.0f; + break; - case DisplayAspectRatio::R5_4: - precise_x = (precise_x * 16.0f) / 15.0f; - break; + case DisplayAspectRatio::R5_4: + precise_x = (precise_x * 16.0f) / 15.0f; + break; - case DisplayAspectRatio::R3_2: - precise_x = (precise_x * 8.0f) / 9.0f; - break; + case DisplayAspectRatio::R3_2: + precise_x = (precise_x * 8.0f) / 9.0f; + break; - case DisplayAspectRatio::R2_1: - precise_x = (precise_x * 2.0f) / 3.0f; - break; + case DisplayAspectRatio::R2_1: + precise_x = (precise_x * 2.0f) / 3.0f; + break; - case DisplayAspectRatio::R1_1: - precise_x = (precise_x * 7.0f) / 6.0f; - break; + case DisplayAspectRatio::R1_1: + precise_x = (precise_x * 7.0f) / 6.0f; + break; - case DisplayAspectRatio::Auto: - case DisplayAspectRatio::R4_3: - case DisplayAspectRatio::PAR1_1: - default: - break; - } - precise_x += fofx; - } - else - { - precise_x = fofx + (precise_ir1 * precise_h_div_sz); + case DisplayAspectRatio::MatchWindow: + case DisplayAspectRatio::Custom: + precise_x = precise_x * s_custom_aspect_ratio_f; + break; + + case DisplayAspectRatio::Auto: + case DisplayAspectRatio::R4_3: + case DisplayAspectRatio::PAR1_1: + default: + break; } + precise_x += fofx; + float precise_y = fofy + (precise_ir2 * precise_h_div_sz); precise_x = std::clamp(precise_x, -1024.0f, 1023.0f); diff --git a/src/core/gte.h b/src/core/gte.h index 716148c13..217a897b7 100644 --- a/src/core/gte.h +++ b/src/core/gte.h @@ -8,6 +8,7 @@ namespace GTE { void Initialize(); void Reset(); bool DoState(StateWrapper& sw); +void UpdateAspectRatio(); // control registers are offset by +32 u32 ReadRegister(u32 index); diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 78095a2d9..cd025bd91 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -533,6 +533,8 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetIntValue("Display", "LineEndOffset", 0); si.SetStringValue("Display", "AspectRatio", Settings::GetDisplayAspectRatioName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)); + si.SetIntValue("Display", "CustomAspectRatioNumerator", 4); + si.GetIntValue("Display", "CustomAspectRatioDenominator", 3); si.SetBoolValue("Display", "Force4_3For24Bit", false); si.SetBoolValue("Display", "LinearFiltering", true); si.SetBoolValue("Display", "IntegerScaling", false); @@ -803,6 +805,14 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings) g_gpu->UpdateSettings(); } + if (g_settings.display_aspect_ratio != old_settings.display_aspect_ratio || + (g_settings.display_aspect_ratio == DisplayAspectRatio::Custom && + (g_settings.display_aspect_ratio_custom_numerator != old_settings.display_aspect_ratio_custom_numerator || + g_settings.display_aspect_ratio_custom_denominator != old_settings.display_aspect_ratio_custom_denominator))) + { + GTE::UpdateAspectRatio(); + } + if (g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable || (g_settings.gpu_pgxp_enable && (g_settings.gpu_pgxp_culling != old_settings.gpu_pgxp_culling || g_settings.gpu_pgxp_cpu != old_settings.gpu_pgxp_cpu))) @@ -899,6 +909,15 @@ void HostInterface::SetUserDirectoryToProgramDirectory() m_user_directory = program_directory; } +void HostInterface::OnHostDisplayResized() +{ + if (System::IsValid()) + { + if (g_settings.display_aspect_ratio == DisplayAspectRatio::MatchWindow) + GTE::UpdateAspectRatio(); + } +} + std::string HostInterface::GetUserDirectoryRelativePath(const char* format, ...) const { std::va_list ap; diff --git a/src/core/host_interface.h b/src/core/host_interface.h index 945b4fcdc..debce9633 100644 --- a/src/core/host_interface.h +++ b/src/core/host_interface.h @@ -183,6 +183,9 @@ protected: /// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates. virtual void SetMouseMode(bool relative, bool hide_cursor); + /// Call when host display size changes, use with "match display" aspect ratio setting. + virtual void OnHostDisplayResized(); + /// Sets the user directory to the program directory, i.e. "portable mode". void SetUserDirectoryToProgramDirectory(); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 0a45b4bed..d44559794 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -3,6 +3,7 @@ #include "common/file_system.h" #include "common/make_array.h" #include "common/string_util.h" +#include "host_display.h" #include "host_interface.h" #include #include @@ -222,6 +223,10 @@ void Settings::Load(SettingsInterface& si) ParseDisplayAspectRatio( si.GetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(DEFAULT_DISPLAY_ASPECT_RATIO)).c_str()) .value_or(DEFAULT_DISPLAY_ASPECT_RATIO); + display_aspect_ratio_custom_numerator = static_cast( + std::clamp(si.GetIntValue("Display", "CustomAspectRatioNumerator", 4), 1, std::numeric_limits::max())); + display_aspect_ratio_custom_denominator = static_cast( + std::clamp(si.GetIntValue("Display", "CustomAspectRatioDenominator", 3), 1, std::numeric_limits::max())); display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false); display_active_start_offset = static_cast(si.GetIntValue("Display", "ActiveStartOffset", 0)); display_active_end_offset = static_cast(si.GetIntValue("Display", "ActiveEndOffset", 0)); @@ -395,6 +400,8 @@ void Settings::Save(SettingsInterface& si) const si.SetIntValue("Display", "LineEndOffset", display_line_end_offset); si.SetBoolValue("Display", "Force4_3For24Bit", display_force_4_3_for_24bit); si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio)); + si.SetIntValue("Display", "CustomAspectRatioNumerator", display_aspect_ratio_custom_numerator); + si.GetIntValue("Display", "CustomAspectRatioDenominator", display_aspect_ratio_custom_denominator); si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering); si.SetBoolValue("Display", "IntegerScaling", display_integer_scaling); si.SetBoolValue("Display", "Stretch", display_stretch); @@ -767,12 +774,12 @@ const char* Settings::GetDisplayCropModeDisplayName(DisplayCropMode crop_mode) return s_display_crop_mode_display_names[static_cast(crop_mode)]; } -static std::array s_display_aspect_ratio_names = { - {TRANSLATABLE("DisplayAspectRatio", "Auto (Game Native)"), "4:3", "16:9", "16:10", "19:9", "20:9", "21:9", "32:9", - "8:7", "5:4", "3:2", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}}; -static constexpr std::array s_display_aspect_ratio_values = { - {-1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 20.0f / 9.0f, 64.0f / 27.0f, 32.0f / 9.0f, - 8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f, 2.0f / 1.0f, 1.0f, -1.0f}}; +static std::array s_display_aspect_ratio_names = { + {TRANSLATABLE("DisplayAspectRatio", "Auto (Game Native)"), "Auto (Match Window)", "Custom", "4:3", "16:9", "16:10", + "19:9", "20:9", "21:9", "32:9", "8:7", "5:4", "3:2", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}}; +static constexpr std::array s_display_aspect_ratio_values = { + {-1.0f, -1.0f, -1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 20.0f / 9.0f, 64.0f / 27.0f, + 32.0f / 9.0f, 8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f, 2.0f / 1.0f, 1.0f, -1.0f}}; std::optional Settings::ParseDisplayAspectRatio(const char* str) { @@ -793,9 +800,32 @@ const char* Settings::GetDisplayAspectRatioName(DisplayAspectRatio ar) return s_display_aspect_ratio_names[static_cast(ar)]; } -float Settings::GetDisplayAspectRatioValue(DisplayAspectRatio ar) +float Settings::GetDisplayAspectRatioValue() const { - return s_display_aspect_ratio_values[static_cast(ar)]; + switch (display_aspect_ratio) + { + case DisplayAspectRatio::MatchWindow: + { + const HostDisplay* display = g_host_interface->GetDisplay(); + if (!display) + return s_display_aspect_ratio_values[static_cast(DEFAULT_DISPLAY_ASPECT_RATIO)]; + + const u32 width = display->GetWindowWidth(); + const u32 height = display->GetWindowHeight() - display->GetDisplayTopMargin(); + return static_cast(width) / static_cast(height); + } + + case DisplayAspectRatio::Custom: + { + return static_cast(display_aspect_ratio_custom_numerator) / + static_cast(display_aspect_ratio_custom_denominator); + } + + default: + { + return s_display_aspect_ratio_values[static_cast(display_aspect_ratio)]; + } + } } static std::array s_audio_backend_names = {{ diff --git a/src/core/settings.h b/src/core/settings.h index 352ab4d5b..71e24e74a 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -127,6 +127,8 @@ struct Settings bool gpu_pgxp_depth_buffer = false; DisplayCropMode display_crop_mode = DisplayCropMode::None; DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::Auto; + u16 display_aspect_ratio_custom_numerator = 0; + u16 display_aspect_ratio_custom_denominator = 0; s16 display_active_start_offset = 0; s16 display_active_end_offset = 0; s8 display_line_start_offset = 0; @@ -256,6 +258,8 @@ struct Settings return audio_output_muted ? 0 : (fast_forwarding ? audio_fast_forward_volume : audio_output_volume); } + float GetDisplayAspectRatioValue() const; + bool HasAnyPerGameMemoryCards() const; static void CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator); @@ -316,7 +320,6 @@ struct Settings static std::optional ParseDisplayAspectRatio(const char* str); static const char* GetDisplayAspectRatioName(DisplayAspectRatio ar); - static float GetDisplayAspectRatioValue(DisplayAspectRatio ar); static std::optional ParseAudioBackend(const char* str); static const char* GetAudioBackendName(AudioBackend backend); diff --git a/src/core/types.h b/src/core/types.h index 07455237b..8ad8f7611 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -94,6 +94,8 @@ enum class DisplayCropMode : u8 enum class DisplayAspectRatio : u8 { Auto, + MatchWindow, + Custom, R4_3, R16_9, R16_10, diff --git a/src/duckstation-qt/displaysettingswidget.cpp b/src/duckstation-qt/displaysettingswidget.cpp index 2b28f468f..1f00148f1 100644 --- a/src/duckstation-qt/displaysettingswidget.cpp +++ b/src/duckstation-qt/displaysettingswidget.cpp @@ -25,6 +25,10 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayAspectRatio, "Display", "AspectRatio", &Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName, Settings::DEFAULT_DISPLAY_ASPECT_RATIO); + SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, m_ui.customAspectRatioNumerator, "Display", + "CustomAspectRatioNumerator", 1); + SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, m_ui.customAspectRatioDenominator, "Display", + "CustomAspectRatioDenominator", 1); SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayCropMode, "Display", "CropMode", &Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName, Settings::DEFAULT_DISPLAY_CROP_MODE); @@ -59,10 +63,13 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW &DisplaySettingsWidget::onGPUAdapterIndexChanged); connect(m_ui.fullscreenMode, QOverload::of(&QComboBox::currentIndexChanged), this, &DisplaySettingsWidget::onGPUFullscreenModeIndexChanged); + connect(m_ui.displayAspectRatio, QOverload::of(&QComboBox::currentIndexChanged), this, + &DisplaySettingsWidget::onAspectRatioChanged); connect(m_ui.displayIntegerScaling, &QCheckBox::stateChanged, this, &DisplaySettingsWidget::onIntegerFilteringChanged); populateGPUAdaptersAndResolutions(); onIntegerFilteringChanged(); + onAspectRatioChanged(); dialog->registerWidgetHelp( m_ui.renderer, tr("Renderer"), @@ -283,3 +290,13 @@ void DisplaySettingsWidget::onIntegerFilteringChanged() m_ui.displayLinearFiltering->setEnabled(!m_ui.displayIntegerScaling->isChecked()); m_ui.displayStretch->setEnabled(!m_ui.displayIntegerScaling->isChecked()); } + +void DisplaySettingsWidget::onAspectRatioChanged() +{ + const bool is_custom = + static_cast(m_ui.displayAspectRatio->currentIndex()) == DisplayAspectRatio::Custom; + + m_ui.customAspectRatioNumerator->setVisible(is_custom); + m_ui.customAspectRatioDenominator->setVisible(is_custom); + m_ui.customAspectRatioSeparator->setVisible(is_custom); +} diff --git a/src/duckstation-qt/displaysettingswidget.h b/src/duckstation-qt/displaysettingswidget.h index d582de82a..b3fcbc3a6 100644 --- a/src/duckstation-qt/displaysettingswidget.h +++ b/src/duckstation-qt/displaysettingswidget.h @@ -21,6 +21,7 @@ private Q_SLOTS: void onGPUAdapterIndexChanged(); void onGPUFullscreenModeIndexChanged(); void onIntegerFilteringChanged(); + void onAspectRatioChanged(); private: void setupAdditionalUi(); diff --git a/src/duckstation-qt/displaysettingswidget.ui b/src/duckstation-qt/displaysettingswidget.ui index 9ac7ca856..05e497589 100644 --- a/src/duckstation-qt/displaysettingswidget.ui +++ b/src/duckstation-qt/displaysettingswidget.ui @@ -111,7 +111,38 @@ - + + + + + + + + 1 + + + 9999 + + + + + + + : + + + + + + + 1 + + + 9999 + + + + diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 310305111..beb508837 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -575,6 +575,8 @@ void CommonHostInterface::OnHostDisplayResized() const u32 new_height = m_display ? m_display->GetWindowHeight() : 0; const float new_scale = m_display ? m_display->GetWindowScale() : 1.0f; + HostInterface::OnHostDisplayResized(); + ImGui::GetIO().DisplaySize.x = static_cast(new_width); ImGui::GetIO().DisplaySize.y = static_cast(new_height); diff --git a/src/frontend-common/common_host_interface.h b/src/frontend-common/common_host_interface.h index 8061f8720..277073495 100644 --- a/src/frontend-common/common_host_interface.h +++ b/src/frontend-common/common_host_interface.h @@ -412,13 +412,13 @@ protected: void UpdateSpeedLimiterState(); void RecreateSystem() override; + void OnHostDisplayResized() override; void ApplyGameSettings(bool display_osd_messages); void ApplyControllerCompatibilitySettings(u64 controller_mask, bool display_osd_messages); bool CreateHostDisplayResources(); void ReleaseHostDisplayResources(); - void OnHostDisplayResized(); virtual void DrawImGuiWindows();