Do not crop kNoBorder menus on widescreen

This commit is contained in:
Eddoursul 2026-07-30 22:11:28 +02:00
parent 1b2eccfd6c
commit e610f6b796

View File

@ -1,15 +1,17 @@
#pragma once #pragma once
// Restores the Scaleform scale modes menus were loaded with before Skyrim 1.6.1130. // Restores the Scaleform scale modes menus were loaded with before Skyrim 1.6.1130, and stops
// kNoBorder from cropping them on displays wider than 16:9.
// //
// 1.6.1130 switched nearly every menu to kExactFit, which stretches the movie across the whole // 1.6.1130 switched nearly every menu to kExactFit, which stretches the movie across the whole
// viewport instead of preserving its aspect ratio. Enderal's menus - including the SkyUI-derived // viewport instead of preserving its aspect ratio. Enderal's menus - including the SkyUI-derived
// widescreen versions shipped with them - are authored for the old modes, so on anything that is // widescreen versions shipped with them - are authored for the old modes, so on anything that is
// not 16:9 they come out distorted. // not 16:9 they come out distorted.
// //
// The table below is what 1.6.640 passes to BSScaleformManager::LoadMovie. Menus the update left // The table below is what 1.6.640 passes to BSScaleformManager::LoadMovie, plus BookMenu and
// alone (Book, BookMenu, Console, CreditsMenu, CursorMenu, FaderMenu, GiftMenu, StartMenu) are // GiftMenu, which 1.6.1130 left on kNoBorder and which need the same clamp. Menus that want no
// deliberately absent and keep whatever the caller asked for. // help (Book, Console, CreditsMenu, CursorMenu, FaderMenu, StartMenu) are absent and keep
// whatever the caller asked for.
// //
// Based on Widescreen Scale Removed by SkyHorizon (GPL-3.0) // Based on Widescreen Scale Removed by SkyHorizon (GPL-3.0)
// https://www.nexusmods.com/skyrimspecialedition/mods/136793 // https://www.nexusmods.com/skyrimspecialedition/mods/136793
@ -34,9 +36,11 @@ namespace MenuAspectRatioFix
{ "TweenMenu"sv, ScaleModeType::kShowAll }, { "TweenMenu"sv, ScaleModeType::kShowAll },
{ "BarterMenu"sv, ScaleModeType::kNoBorder }, { "BarterMenu"sv, ScaleModeType::kNoBorder },
{ "BookMenu"sv, ScaleModeType::kNoBorder },
{ "ContainerMenu"sv, ScaleModeType::kNoBorder }, { "ContainerMenu"sv, ScaleModeType::kNoBorder },
{ "CraftingMenu"sv, ScaleModeType::kNoBorder }, { "CraftingMenu"sv, ScaleModeType::kNoBorder },
{ "DialogueMenu"sv, ScaleModeType::kNoBorder }, { "DialogueMenu"sv, ScaleModeType::kNoBorder },
{ "GiftMenu"sv, ScaleModeType::kNoBorder },
{ "InventoryMenu"sv, ScaleModeType::kNoBorder }, { "InventoryMenu"sv, ScaleModeType::kNoBorder },
{ "LockpickingMenu"sv, ScaleModeType::kNoBorder }, { "LockpickingMenu"sv, ScaleModeType::kNoBorder },
{ "MagicMenu"sv, ScaleModeType::kNoBorder }, { "MagicMenu"sv, ScaleModeType::kNoBorder },
@ -53,13 +57,38 @@ namespace MenuAspectRatioFix
return it != modes.end() ? std::optional{ it->second } : std::nullopt; return it != modes.end() ? std::optional{ it->second } : std::nullopt;
} }
// The movie gets the whole framebuffer as its viewport, so kNoBorder scales a 1280x720 menu
// until it covers the full width and crops whatever no longer fits: at 32:9 that is a 2x zoom
// with half the menu off screen. Past 16:9 it can only ever crop, so hand out kShowAll instead -
// that keeps the 16:9 scale and merely leaves more of the stage surroundings visible, which is
// exactly what SkyUI's widescreen menus stretch their bars over (they cover up to 32:9).
// Narrower than 16:9 kNoBorder is still the better answer: it hides the strips above and below
// the stage that kShowAll would expose.
ScaleModeType ClampToViewport(ScaleModeType a_mode)
{
if (a_mode != ScaleModeType::kNoBorder) {
return a_mode;
}
const auto state = RE::BSGraphics::State::GetSingleton();
if (!state || state->screenHeight == 0) {
return a_mode;
}
// Every vanilla menu is authored on a 1280x720 stage
constexpr float stageAspect = 1280.0f / 720.0f;
const float viewportAspect = static_cast<float>(state->screenWidth) / static_cast<float>(state->screenHeight);
return viewportAspect > stageAspect ? ScaleModeType::kShowAll : a_mode;
}
struct LoadMovie struct LoadMovie
{ {
static bool thunk(RE::BSScaleformManager* a_scaleformManager, RE::IMenu* a_menu, RE::GPtr<RE::GFxMovieView>& a_viewOut, const char* a_fileName, ScaleModeType a_mode, float a_backgroundAlpha) static bool thunk(RE::BSScaleformManager* a_scaleformManager, RE::IMenu* a_menu, RE::GPtr<RE::GFxMovieView>& a_viewOut, const char* a_fileName, ScaleModeType a_mode, float a_backgroundAlpha)
{ {
if (a_fileName && a_fileName[0]) { if (a_fileName && a_fileName[0]) {
if (const auto mode = GetScaleMode(a_fileName); mode) { if (const auto mode = GetScaleMode(a_fileName); mode) {
a_mode = *mode; a_mode = ClampToViewport(*mode);
} }
} }