From 2db40408434459c7dcb25f3ab37dff758c6763c8 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 16 Apr 2026 22:47:02 -0600 Subject: [PATCH] Make HUD viewport respect SDL_GetWindowSafeArea --- include/m_Do/m_Do_graphic.h | 20 ++++++++- src/d/d_bright_check.cpp | 2 +- src/d/d_file_select.cpp | 13 ++++-- src/d/d_menu_collect.cpp | 10 ++++- src/d/d_menu_save.cpp | 2 +- src/m_Do/m_Do_graphic.cpp | 89 ++++++++++++++++++++++++++++++++++++- src/m_Do/m_Do_lib.cpp | 2 +- 7 files changed, 125 insertions(+), 13 deletions(-) diff --git a/include/m_Do/m_Do_graphic.h b/include/m_Do/m_Do_graphic.h index c6b22654fa..f921912656 100644 --- a/include/m_Do/m_Do_graphic.h +++ b/include/m_Do/m_Do_graphic.h @@ -125,8 +125,15 @@ public: #if TARGET_PC static f32 hudAspectScaleDown; static f32 hudAspectScaleUp; - static f32 ScaleHUDXLeft(f32 baseX) { return getMinXF() + baseX; } - static f32 ScaleHUDXRight(f32 baseX) { return -getMinXF() + baseX; } + static void updateSafeAreaBounds(); + static f32 getSafeMinXF() { return m_safeMinXF; } + static f32 getSafeMinYF() { return m_safeMinYF; } + static f32 getSafeWidthF() { return m_safeWidthF; } + static f32 getSafeHeightF() { return m_safeHeightF; } + static f32 getSafeMaxXF() { return m_safeMaxXF; } + static f32 getSafeMaxYF() { return m_safeMaxYF; } + static f32 ScaleHUDXLeft(f32 baseX) { return getSafeMinXF() + baseX; } + static f32 ScaleHUDXRight(f32 baseX) { return getSafeMaxXF() - FB_WIDTH_BASE + baseX; } #endif static void setBlureMtx(const Mtx m) { @@ -369,6 +376,15 @@ public: static int m_height; static f32 m_heightF; static f32 m_widthF; + + #if TARGET_PC + static f32 m_safeMinXF; + static f32 m_safeMinYF; + static f32 m_safeMaxXF; + static f32 m_safeMaxYF; + static f32 m_safeWidthF; + static f32 m_safeHeightF; + #endif #endif }; diff --git a/src/d/d_bright_check.cpp b/src/d/d_bright_check.cpp index ac28e46838..c3fcc806d5 100644 --- a/src/d/d_bright_check.cpp +++ b/src/d/d_bright_check.cpp @@ -147,7 +147,7 @@ void dBrightCheck_c::modeMove() { void dBrightCheck_c::brightCheckWide() { // Main Canvas mBrightCheck.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); - mBrightCheck.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + mBrightCheck.Scr->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); // Right Square mBrightCheck.Scr->search(MULTI_CHAR('fuchi_1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); diff --git a/src/d/d_file_select.cpp b/src/d/d_file_select.cpp index be40b13d1c..550c5b3e52 100644 --- a/src/d/d_file_select.cpp +++ b/src/d/d_file_select.cpp @@ -3776,7 +3776,7 @@ bool dFile_select_c::yesnoWakuAlpahAnm(u8 param_1) { #if TARGET_PC void dFile_select_c::fileSelectWide() { mYnSel.ScrYn->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); - mYnSel.ScrYn->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + mYnSel.ScrYn->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); mYnSel.ScrYn->search(MULTI_CHAR('w_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); mYnSel.ScrYn->search(MULTI_CHAR('f_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); @@ -3784,7 +3784,7 @@ void dFile_select_c::fileSelectWide() { mYnSel.ScrYn->search(MULTI_CHAR('f_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); m3mSel.Scr3m->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); - m3mSel.Scr3m->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + m3mSel.Scr3m->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); m3mSel.Scr3m->search(MULTI_CHAR('w_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); m3mSel.Scr3m->search(MULTI_CHAR('f_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); @@ -3794,7 +3794,7 @@ void dFile_select_c::fileSelectWide() { m3mSel.Scr3m->search(MULTI_CHAR('f_cop_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); fileSel.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); - fileSel.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + fileSel.Scr->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); fileSel.Scr->search(MULTI_CHAR('t_for'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); fileSel.Scr->search(MULTI_CHAR('t_for1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); @@ -5584,7 +5584,13 @@ void dFile_select3D_c::createMirrorModel() { void dFile_select3D_c::toItem3Dpos(f32 param_0, f32 param_1, f32 param_2, cXyz* param_3) { Mtx adStack_98; Mtx auStack_c8; +#if TARGET_PC + param_0 = + (2.0f * ((param_0 - mDoGph_gInf_c::getSafeMinXF()) / mDoGph_gInf_c::getSafeWidthF()) - + 1.0f); +#else param_0 = (2.0f * ((param_0 - mDoGph_gInf_c::getMinXF()) / mDoGph_gInf_c::getWidthF()) - 1.0f); +#endif param_1 = (2.0f * ((param_1 - -100.0f) / FB_HEIGHT_BASE) - 1.0f); calcViewMtx(adStack_98); cMtx_inverse(adStack_98, auStack_c8); @@ -5601,4 +5607,3 @@ void dFile_select3D_c::calcViewMtx(Mtx param_0) { cXyz pos2(0.0f, 1.0f, 0.0f); cMtx_lookAt(param_0, &pos1, &cXyz::Zero, &pos2, 0); } - diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index c7e5bb7414..7ae416c4be 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -99,7 +99,7 @@ dMenu_Collect2D_c::~dMenu_Collect2D_c() { void dMenu_Collect2D_c::menuCollectWide() { // Main Canvas mpScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); - mpScreen->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + mpScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); // Pieces of Heart mpScreen->search(MULTI_CHAR('heart_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); @@ -182,7 +182,7 @@ void dMenu_Collect2D_c::_create() { } #if TARGET_PC - mpScreenIcon->translate(-mDoGph_gInf_c::getMinXF(), 0.0f); + mpScreenIcon->translate(-mDoGph_gInf_c::getSafeMinXF(), 0.0f); #endif dPaneClass_showNullPane(mpScreenIcon); @@ -2706,8 +2706,14 @@ void dMenu_Collect3D_c::setupItem3D(Mtx param_0) { void dMenu_Collect3D_c::toItem3Dpos(f32 param_0, f32 param_1, f32 param_2, cXyz* param_3) { Mtx adStack_98; Mtx auStack_c8; +#if TARGET_PC + param_0 = + (2.0f * ((param_0 - mDoGph_gInf_c::getSafeMinXF()) / mDoGph_gInf_c::getSafeWidthF()) - + 1.0f); +#else param_0 = (2.0f * ((param_0 - mDoGph_gInf_c::getMinXF()) / mDoGph_gInf_c::getWidthF()) - 1.0f); +#endif param_1 = (2.0f * ((param_1 - -100.0f) / FB_HEIGHT_BASE) - 1.0f); calcViewMtx(adStack_98); MTXInverse(adStack_98, auStack_c8); diff --git a/src/d/d_menu_save.cpp b/src/d/d_menu_save.cpp index 618677866b..0935eb4e52 100644 --- a/src/d/d_menu_save.cpp +++ b/src/d/d_menu_save.cpp @@ -2782,7 +2782,7 @@ void dMenu_save_c::_draw() { #if TARGET_PC void dMenu_save_c::menuSaveWide() { mSaveSel.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); - mSaveSel.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + mSaveSel.Scr->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); mSaveSel.Scr->search(MULTI_CHAR('t_for'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); mSaveSel.Scr->search(MULTI_CHAR('t_for1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index d774a7de7d..a56e448645 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -47,6 +47,8 @@ #endif #if TARGET_PC +#include +#include "aurora/lib/window.hpp" #include "d/actor/d_a_horse.h" #include "dusk/dusk.h" #include "dusk/endian.h" @@ -636,8 +638,9 @@ void mDoGph_gInf_c::setTvSize() { m_invScale = 1.0f / m_scale; #if TARGET_PC - hudAspectScaleDown = 1.3571428f / mDoGph_gInf_c::getAspect(); - hudAspectScaleUp = 1.0f / hudAspectScaleDown; + updateSafeAreaBounds(); + hudAspectScaleUp = getSafeWidthF() / FB_WIDTH_BASE; + hudAspectScaleDown = FB_WIDTH_BASE / getSafeWidthF(); #endif } @@ -765,6 +768,88 @@ void mDoGph_gInf_c::setWideZoomLightProjection(Mtx& m) { #if TARGET_PC f32 mDoGph_gInf_c::hudAspectScaleDown = 1.0f; f32 mDoGph_gInf_c::hudAspectScaleUp = 1.0f; +f32 mDoGph_gInf_c::m_safeMinXF = 0.0f; +f32 mDoGph_gInf_c::m_safeMinYF = 0.0f; +f32 mDoGph_gInf_c::m_safeMaxXF = FB_WIDTH_BASE; +f32 mDoGph_gInf_c::m_safeMaxYF = FB_HEIGHT_BASE; +f32 mDoGph_gInf_c::m_safeWidthF = FB_WIDTH_BASE; +f32 mDoGph_gInf_c::m_safeHeightF = FB_HEIGHT_BASE; + +void mDoGph_gInf_c::updateSafeAreaBounds() { + m_safeMinXF = m_minXF; + m_safeMinYF = m_minYF; + m_safeMaxXF = m_maxXF; + m_safeMaxYF = m_maxYF; + m_safeWidthF = m_widthF; + m_safeHeightF = m_heightF; + + SDL_Window* window = aurora::window::get_sdl_window(); + if (window == NULL) { + return; + } + + const AuroraWindowSize windowSize = aurora::window::get_window_size(); + const f32 windowWidth = static_cast(windowSize.width); + const f32 windowHeight = static_cast(windowSize.height); + if (windowWidth <= 0.0f || windowHeight <= 0.0f) { + return; + } + + SDL_Rect safeRect{}; + if (!SDL_GetWindowSafeArea(window, &safeRect)) { + return; + } + + if (windowSize.native_fb_width == 0 || windowSize.native_fb_height == 0 || + windowSize.fb_width == 0 || windowSize.fb_height == 0) + { + return; + } + + const f32 nativeScaleX = static_cast(windowSize.native_fb_width) / windowWidth; + const f32 nativeScaleY = static_cast(windowSize.native_fb_height) / windowHeight; + + const f32 safeLeft = static_cast(safeRect.x) * nativeScaleX; + const f32 safeTop = static_cast(safeRect.y) * nativeScaleY; + const f32 safeRight = static_cast(safeRect.x + safeRect.w) * nativeScaleX; + const f32 safeBottom = static_cast(safeRect.y + safeRect.h) * nativeScaleY; + + const f32 viewportLeft = + (static_cast(windowSize.native_fb_width) - static_cast(windowSize.fb_width)) * + 0.5f; + const f32 viewportTop = + (static_cast(windowSize.native_fb_height) - static_cast(windowSize.fb_height)) * + 0.5f; + const f32 viewportRight = viewportLeft + static_cast(windowSize.fb_width); + const f32 viewportBottom = viewportTop + static_cast(windowSize.fb_height); + + const f32 leftInset = std::max(0.0f, safeLeft - viewportLeft) * + (m_widthF / static_cast(windowSize.fb_width)); + const f32 topInset = std::max(0.0f, safeTop - viewportTop) * + (m_heightF / static_cast(windowSize.fb_height)); + const f32 rightInset = std::max(0.0f, viewportRight - safeRight) * + (m_widthF / static_cast(windowSize.fb_width)); + const f32 bottomInset = std::max(0.0f, viewportBottom - safeBottom) * + (m_heightF / static_cast(windowSize.fb_height)); + + const f32 safeMinXF = m_minXF + leftInset; + const f32 safeMinYF = m_minYF + topInset; + const f32 safeMaxXF = m_maxXF - rightInset; + const f32 safeMaxYF = m_maxYF - bottomInset; + const f32 safeWidthF = safeMaxXF - safeMinXF; + const f32 safeHeightF = safeMaxYF - safeMinYF; + + if (safeWidthF <= 0.0f || safeHeightF <= 0.0f) { + return; + } + + m_safeMinXF = safeMinXF; + m_safeMinYF = safeMinYF; + m_safeMaxXF = safeMaxXF; + m_safeMaxYF = safeMaxYF; + m_safeWidthF = safeWidthF; + m_safeHeightF = safeHeightF; +} void mDoGph_gInf_c::setWindowSize(AuroraWindowSize const& size) { JUTVideo::getManager()->setWindowSize(size); diff --git a/src/m_Do/m_Do_lib.cpp b/src/m_Do/m_Do_lib.cpp index 93df5c23cc..b541490353 100644 --- a/src/m_Do/m_Do_lib.cpp +++ b/src/m_Do/m_Do_lib.cpp @@ -154,7 +154,7 @@ void mDoLib_project(Vec* src, Vec* dst, JGeometry::TBox2 viewport) { xSize = FB_WIDTH; } else { #if TARGET_PC - xOffset = mDoGph_gInf_c::getMinXF(); + xOffset = mDoGph_gInf_c::getSafeMinXF(); xSize = viewport.f.x * mDoGph_gInf_c::hudAspectScaleUp; #else xOffset = viewport.i.x;