Added Widescreen Scale Removed by SkyHorizon
This commit is contained in:
parent
ce55b39a25
commit
1b2eccfd6c
@ -9,3 +9,4 @@ AttachLightHitEffectCrashFix = true
|
||||
AutoScaleHeroMenu = true
|
||||
WarnFormTypeCollisions = true
|
||||
GogVramLeakFix = true
|
||||
MenuAspectRatioFix = true
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#include "Patches/FormTypeCollisionDetector.h"
|
||||
#include "Patches/GogVramLeakFix.h"
|
||||
#include "Patches/ForceLanguage.h"
|
||||
#include "Patches/MenuAspectRatioFix.h"
|
||||
|
||||
using namespace SKSE;
|
||||
|
||||
@ -31,7 +32,8 @@ static std::map<std::string, bool> g_settings{
|
||||
{ "ForceBorderless", true },
|
||||
{ "AttachLightHitEffectCrashFix", true },
|
||||
{ "AutoScaleHeroMenu", true },
|
||||
{ "GogVramLeakFix", true }
|
||||
{ "GogVramLeakFix", true },
|
||||
{ "MenuAspectRatioFix", true }
|
||||
};
|
||||
|
||||
namespace {
|
||||
@ -252,6 +254,10 @@ SKSEPluginLoad(const LoadInterface* skse) {
|
||||
logger::info("Initializing Stay At The System Page...");
|
||||
JournalMenuEx::InstallHooks();
|
||||
}
|
||||
// Menus are only stretched to fill the viewport since 1.6.1130
|
||||
if (g_settings.at("MenuAspectRatioFix") && REL::Module::get().version() >= REL::Version(1, 6, 1130, 0)) {
|
||||
MenuAspectRatioFix::Install();
|
||||
}
|
||||
}
|
||||
|
||||
logger::info("{} has finished loading.", plugin->GetName());
|
||||
|
||||
@ -37,4 +37,41 @@ namespace SKSE::stl
|
||||
auto& trampoline = SKSE::GetTrampoline();
|
||||
T::func = trampoline.write_branch<N>(a_src, T::thunk);
|
||||
}
|
||||
|
||||
// Detours a whole function: the first BYTES bytes are copied into the trampoline and followed by
|
||||
// a jump back into the original, so T::func is a callable stand-in for the untouched function.
|
||||
// BYTES must cover complete, position-independent instructions and be at least 5.
|
||||
// Costs 14 bytes of trampoline for the branch island plus BYTES + 14 for the stub.
|
||||
// Thanks Nukem and po3, via Widescreen Scale Removed by SkyHorizon (GPL-3.0).
|
||||
template <class T, std::size_t BYTES>
|
||||
void hook_function_prologue(std::uintptr_t a_src)
|
||||
{
|
||||
static_assert(BYTES >= 5, "not enough room for a jump");
|
||||
|
||||
// Xbyak::CodeGenerator has a member function std() - the STD instruction - which hides the
|
||||
// namespace inside the class body, hence the leading :: on every std:: name below
|
||||
struct Stub : Xbyak::CodeGenerator
|
||||
{
|
||||
Stub(std::uintptr_t a_target, std::size_t a_size)
|
||||
{
|
||||
for (::std::size_t i = 0; i < a_size; ++i) {
|
||||
db(*reinterpret_cast<const ::std::uint8_t*>(a_target + i));
|
||||
}
|
||||
|
||||
jmp(ptr[rip]);
|
||||
dq(a_target + a_size);
|
||||
}
|
||||
};
|
||||
|
||||
Stub stub(a_src, BYTES);
|
||||
stub.ready();
|
||||
|
||||
auto& trampoline = SKSE::GetTrampoline();
|
||||
auto* mem = trampoline.allocate(stub.getSize());
|
||||
std::memcpy(mem, stub.getCode(), stub.getSize());
|
||||
|
||||
// Publish the stand-in before redirecting the function, the thunk needs it on its first call
|
||||
T::func = reinterpret_cast<std::uintptr_t>(mem);
|
||||
trampoline.write_branch<5>(a_src, T::thunk);
|
||||
}
|
||||
}
|
||||
|
||||
91
source/Enderal DLL/src/Patches/MenuAspectRatioFix.h
Normal file
91
source/Enderal DLL/src/Patches/MenuAspectRatioFix.h
Normal file
@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
// Restores the Scaleform scale modes menus were loaded with before Skyrim 1.6.1130.
|
||||
//
|
||||
// 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
|
||||
// widescreen versions shipped with them - are authored for the old modes, so on anything that is
|
||||
// not 16:9 they come out distorted.
|
||||
//
|
||||
// The table below is what 1.6.640 passes to BSScaleformManager::LoadMovie. Menus the update left
|
||||
// alone (Book, BookMenu, Console, CreditsMenu, CursorMenu, FaderMenu, GiftMenu, StartMenu) are
|
||||
// deliberately absent and keep whatever the caller asked for.
|
||||
//
|
||||
// Based on Widescreen Scale Removed by SkyHorizon (GPL-3.0)
|
||||
// https://www.nexusmods.com/skyrimspecialedition/mods/136793
|
||||
namespace MenuAspectRatioFix
|
||||
{
|
||||
using ScaleModeType = RE::GFxMovieView::ScaleModeType;
|
||||
|
||||
std::optional<ScaleModeType> GetScaleMode(const char* a_fileName)
|
||||
{
|
||||
static const std::map<std::string_view, ScaleModeType> modes{
|
||||
{ "FavoritesMenu"sv, ScaleModeType::kShowAll },
|
||||
{ "HUDMenu"sv, ScaleModeType::kShowAll },
|
||||
{ "LevelUpMenu"sv, ScaleModeType::kShowAll },
|
||||
{ "LoadWaitSpinner"sv, ScaleModeType::kShowAll },
|
||||
{ "LoadingMenu"sv, ScaleModeType::kShowAll },
|
||||
{ "Map"sv, ScaleModeType::kShowAll },
|
||||
{ "Quest_Journal"sv, ScaleModeType::kShowAll },
|
||||
{ "SafeZone"sv, ScaleModeType::kShowAll },
|
||||
{ "SleepWaitMenu"sv, ScaleModeType::kShowAll },
|
||||
{ "Titles"sv, ScaleModeType::kShowAll },
|
||||
{ "TutorialMenu"sv, ScaleModeType::kShowAll },
|
||||
{ "TweenMenu"sv, ScaleModeType::kShowAll },
|
||||
|
||||
{ "BarterMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "ContainerMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "CraftingMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "DialogueMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "InventoryMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "LockpickingMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "MagicMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "MessageBox"sv, ScaleModeType::kNoBorder },
|
||||
{ "RaceSex_menu"sv, ScaleModeType::kNoBorder },
|
||||
{ "StatsMenu"sv, ScaleModeType::kNoBorder },
|
||||
{ "TrainingMenu"sv, ScaleModeType::kNoBorder },
|
||||
|
||||
// Replaces CraftingMenu, https://www.nexusmods.com/skyrimspecialedition/mods/81409
|
||||
{ "ConstructibleObjectMenu"sv, ScaleModeType::kNoBorder }
|
||||
};
|
||||
|
||||
const auto it = modes.find(a_fileName);
|
||||
return it != modes.end() ? std::optional{ it->second } : std::nullopt;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (a_fileName && a_fileName[0]) {
|
||||
if (const auto mode = GetScaleMode(a_fileName); mode) {
|
||||
a_mode = *mode;
|
||||
}
|
||||
}
|
||||
|
||||
return func(a_scaleformManager, a_menu, a_viewOut, a_fileName, a_mode, a_backgroundAlpha);
|
||||
}
|
||||
|
||||
static inline REL::Relocation<decltype(thunk)> func;
|
||||
};
|
||||
|
||||
void Install()
|
||||
{
|
||||
// Checked: 1.6.640, 1.6.659, 1.6.1130, 1.6.1170, 1.6.1179
|
||||
const auto target = REL::RelocationID(80302, 82325).address();
|
||||
|
||||
// mov rax,rsp / mov qword ptr [rax+10h],rdx - relocated into the trampoline by the hook,
|
||||
// so bail out rather than corrupt the function if a future runtime changes the prologue
|
||||
constexpr std::uint8_t prologue[]{ 0x48, 0x8B, 0xC4, 0x48, 0x89, 0x50, 0x10 };
|
||||
|
||||
if (!target || std::memcmp(reinterpret_cast<const void*>(target), prologue, sizeof(prologue)) != 0) {
|
||||
logger::error("Unexpected BSScaleformManager::LoadMovie prologue, menu aspect ratio fix is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
SKSE::AllocTrampoline(64);
|
||||
SKSE::stl::hook_function_prologue<LoadMovie, sizeof(prologue)>(target);
|
||||
|
||||
logger::info("Applied menu aspect ratio fix");
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user