Skip to content

Commit

Permalink
Implement widescreen fix
Browse files Browse the repository at this point in the history
  • Loading branch information
doyaGu committed Jun 16, 2024
1 parent edd8437 commit 9961659
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 52 deletions.
45 changes: 15 additions & 30 deletions src/BMLMod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <oniguruma.h>
#include <utf8.h>
#include "imgui_internal.h"

#include "BML/Bui.h"
#include "BML/Gui.h"
Expand All @@ -14,9 +15,9 @@
#include "ModManager.h"
#include "Commands.h"
#include "Config.h"
#include "RenderHook.h"
#include "StringUtils.h"
#include "PathUtils.h"
#include "imgui_internal.h"

namespace ExecuteBB {
void Init();
Expand Down Expand Up @@ -50,26 +51,6 @@ void BMLMod::OnLoadObject(const char *filename, CKBOOL isMap, const char *master
CKBehavior *menuMain = m_BML->GetScriptByName("Menu_Start");
m_ExitStart = FindFirstBB(menuMain, "Exit");
}

if (!strcmp(filename, "3D Entities\\MenuLevel.nmo")) {
if (m_FixWidescreen->GetBoolean()) {
GetLogger()->Info("Adjust MenuLevel Camera");
CKCamera *cam = m_BML->GetTargetCameraByName("Cam_MenuLevel");
cam->SetAspectRatio((int)m_WindowRect.GetWidth(), (int)m_WindowRect.GetHeight());
cam->SetFov(0.75f * m_WindowRect.GetWidth() / m_WindowRect.GetHeight());
m_BML->SetIC(cam);
}
}

if (!strcmp(filename, "3D Entities\\Camera.nmo")) {
if (m_FixWidescreen->GetBoolean()) {
GetLogger()->Info("Adjust Ingame Camera");
CKCamera *cam = m_BML->GetTargetCameraByName("InGameCam");
cam->SetAspectRatio((int)m_WindowRect.GetWidth(), (int)m_WindowRect.GetHeight());
cam->SetFov(0.75f * m_WindowRect.GetWidth() / m_WindowRect.GetHeight());
m_BML->SetIC(cam);
}
}
}

void BMLMod::OnLoadScript(const char *filename, CKBehavior *script) {
Expand Down Expand Up @@ -146,10 +127,10 @@ void BMLMod::OnModifyConfig(const char *category, const char *key, IProperty *pr
if (m_MsgMaxTimer < 2000) {
m_MsgDuration->SetFloat(2.0f);
}
} else if (prop == m_AlphaTestEnabled) {
} else if (prop == m_LanternAlphaTest) {
CKMaterial *mat = m_BML->GetMaterialByName("Laterne_Verlauf");
if (mat) {
CKBOOL atest = m_AlphaTestEnabled->GetBoolean();
CKBOOL atest = m_LanternAlphaTest->GetBoolean();
mat->EnableAlphaTest(atest);

VXCMPFUNC afunc = VXCMP_GREATEREQUAL;
Expand All @@ -158,6 +139,8 @@ void BMLMod::OnModifyConfig(const char *category, const char *key, IProperty *pr
int ref = 0;
mat->SetAlphaRef(ref);
}
} else if (prop == m_WidescreenFix) {
RenderHook::EnableWidescreenFix(m_WidescreenFix->GetBoolean());
} else if (prop == m_Overclock) {
for (int i = 0; i < 3; i++)
m_OverclockLinks[i]->SetOutBehaviorIO(m_OverclockLinkIO[i][m_Overclock->GetBoolean()]);
Expand All @@ -174,6 +157,8 @@ void BMLMod::OnPreStartMenu() {
else
AdjustFrameRate(true);
}

RenderHook::EnableWidescreenFix(m_WidescreenFix->GetBoolean());
}

void BMLMod::OnExitGame() {
Expand Down Expand Up @@ -513,13 +498,13 @@ void BMLMod::InitConfigs() {
m_FPSLimit->SetComment("Set Frame Rate Limitation, this option will not work if frame rate is unlocked. Set to 0 will turn on VSync");
m_FPSLimit->SetDefaultInteger(0);

m_AlphaTestEnabled = GetConfig()->GetProperty("Misc", "EnableAlphaTest");
m_AlphaTestEnabled->SetComment("Enable alpha test for lantern material, this option can increase FPS");
m_AlphaTestEnabled->SetDefaultBoolean(true);
m_LanternAlphaTest = GetConfig()->GetProperty("Misc", "LanternAlphaTest");
m_LanternAlphaTest->SetComment("Enable alpha test for lantern material, this option can increase FPS");
m_LanternAlphaTest->SetDefaultBoolean(true);

m_FixWidescreen = GetConfig()->GetProperty("Misc", "FixWidescreen");
m_FixWidescreen->SetComment("Improve widescreen resolutions support");
m_FixWidescreen->SetDefaultBoolean(true);
m_WidescreenFix = GetConfig()->GetProperty("Misc", "WidescreenFix");
m_WidescreenFix->SetComment("Improve widescreen resolutions support");
m_WidescreenFix->SetDefaultBoolean(false);

m_FixLifeBall = GetConfig()->GetProperty("Misc", "FixLifeBallFreeze");
m_FixLifeBall->SetComment("Game won't freeze when picking up life balls");
Expand Down Expand Up @@ -1138,7 +1123,7 @@ void BMLMod::OnEditScript_Levelinit_build(CKBehavior *script) {

CKParameter *sate = sat->GetInputParameter(0)->GetDirectSource();
if (sate) {
CKBOOL atest = m_AlphaTestEnabled->GetBoolean();
CKBOOL atest = m_LanternAlphaTest->GetBoolean();
sate->SetValue(&atest);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/BMLMod.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ class BMLMod : public IMod {
IProperty *m_ShowSR = nullptr;
IProperty *m_UnlockFPS = nullptr;
IProperty *m_FPSLimit = nullptr;
IProperty *m_AlphaTestEnabled = nullptr;
IProperty *m_FixWidescreen = nullptr;
IProperty *m_LanternAlphaTest = nullptr;
IProperty *m_WidescreenFix = nullptr;
IProperty *m_FixLifeBall = nullptr;
IProperty* m_MsgDuration = nullptr;
IProperty* m_CustomMapNumber = nullptr;
Expand Down
88 changes: 68 additions & 20 deletions src/RenderHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "CKParameterOut.h"
#include "CKRasterizer.h"

#include <MinHook.h>

#include "HookUtils.h"
#include "VTables.h"

Expand Down Expand Up @@ -111,7 +113,7 @@ class CKRenderedScene {
XArray<int> field_54;
};

struct RenderManagerHook : public CKRenderManager {
class CP_HOOK_CLASS_NAME(CKRenderManager) : public CKRenderManager {
public:
XClassArray<VxCallBack> m_TemporaryPreRenderCallbacks;
XClassArray<VxCallBack> m_TemporaryPostRenderCallbacks;
Expand Down Expand Up @@ -255,14 +257,14 @@ struct RenderManagerHook : public CKRenderManager {
return CP_CALL_METHOD_PTR(this, s_VTable.AddEffect, NewEffect);
}

static void Hook(CKRenderManager *man) {
static bool Hook(CKRenderManager *man) {
if (!man)
return;
return false;

utils::LoadVTable<CP_CLASS_VTABLE_NAME(CKRenderManager)<CKRenderManager>>(man, s_VTable);

#define HOOK_RENDER_MANAGER_VIRTUAL_METHOD(Instance, Name) \
utils::HookVirtualMethod(Instance, &RenderManagerHook::CP_FUNC_HOOK_NAME(Name), (offsetof(CP_CLASS_VTABLE_NAME(CKRenderManager)<CKRenderManager>, Name) / sizeof(void*)))
utils::HookVirtualMethod(Instance, &CP_HOOK_CLASS_NAME(CKRenderManager)::CP_FUNC_HOOK_NAME(Name), (offsetof(CP_CLASS_VTABLE_NAME(CKRenderManager)<CKRenderManager>, Name) / sizeof(void*)))

// HOOK_RENDER_MANAGER_VIRTUAL_METHOD(man, GetRenderDriverCount);
// HOOK_RENDER_MANAGER_VIRTUAL_METHOD(man, GetRenderDriverDescription);
Expand All @@ -284,6 +286,8 @@ struct RenderManagerHook : public CKRenderManager {
// HOOK_RENDER_MANAGER_VIRTUAL_METHOD(man, AddEffect);

#undef HOOK_RENDER_MANAGER_VIRTUAL_METHOD

return true;
}

static void Unhook(CKRenderManager *man) {
Expand All @@ -292,17 +296,17 @@ struct RenderManagerHook : public CKRenderManager {
}
};

CP_CLASS_VTABLE_NAME(CKRenderManager)<CKRenderManager> RenderManagerHook::s_VTable = {};
CP_CLASS_VTABLE_NAME(CKRenderManager)<CKRenderManager> CP_HOOK_CLASS_NAME(CKRenderManager)::s_VTable = {};

struct RenderContextHook : public CKRenderContext {
struct CP_HOOK_CLASS_NAME(CKRenderContext) : public CKRenderContext {
CKDWORD m_WinHandle;
CKDWORD m_AppHandle;
CKRECT m_WinRect;
CK_RENDER_FLAGS m_RenderFlags;
CKRenderedScene *m_RenderedScene;
CKBOOL m_Fullscreen;
CKBOOL m_Active;
CKBOOL m_PerspectiveOrOrthographic;
CKBOOL m_Perspective;
CKBOOL m_ProjectionUpdated;
CKBOOL m_Start;
CKBOOL m_TransparentMode;
Expand Down Expand Up @@ -374,7 +378,9 @@ struct RenderContextHook : public CKRenderContext {
CKDWORD m_PVInformation;

static bool s_DisableRender;
static bool s_EnableWidescreenFix;
static CP_CLASS_VTABLE_NAME(CKRenderContext)<CKRenderContext> s_VTable;
CP_DECLARE_METHOD_PTRS(CKRenderContext, CKBOOL, UpdateProjection, (CKBOOL));

CP_DECLARE_METHOD_HOOK(void, AddObject, (CKRenderObject *obj)) {
CP_CALL_METHOD_PTR(this, s_VTable.AddObject, obj);
Expand Down Expand Up @@ -819,14 +825,27 @@ struct RenderContextHook : public CKRenderContext {
CP_CALL_METHOD_PTR(this, s_VTable.GetStereoParameters, EyeSeparation, FocalLength);
}

static void Hook(CKRenderContext *rc) {
CKBOOL CP_FUNC_HOOK_NAME(UpdateProjection)(CKBOOL force) {
const float fov = m_Fov;

if (s_EnableWidescreenFix && m_Perspective) {
const auto aspect = (float) ((double) m_ViewportData.ViewWidth / (double) m_ViewportData.ViewHeight);
m_Fov = atan2f(tanf(m_Fov * 0.5f) * 0.75f * aspect, 1.0f) * 2.0f;
}
auto res = CP_CALL_METHOD_ORIG(UpdateProjection, force);

m_Fov = fov;
return res;
}

static bool Hook(CKRenderContext *rc) {
if (!rc)
return;
return false;

utils::LoadVTable<CP_CLASS_VTABLE_NAME(CKRenderContext)<CKRenderContext>>(rc, s_VTable);

#define HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(Instance, Name) \
utils::HookVirtualMethod(Instance, &RenderContextHook::CP_FUNC_HOOK_NAME(Name), (offsetof(CP_CLASS_VTABLE_NAME(CKRenderContext)<CKRenderContext>, Name) / sizeof(void*)))
utils::HookVirtualMethod(Instance, &CP_HOOK_CLASS_NAME(CKRenderContext)::CP_FUNC_HOOK_NAME(Name), (offsetof(CP_CLASS_VTABLE_NAME(CKRenderContext)<CKRenderContext>, Name) / sizeof(void*)))

// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, AddObject);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, RemoveObject);
Expand All @@ -851,8 +870,8 @@ struct RenderContextHook : public CKRenderContext {
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetDrawPrimitiveIndices);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, Transform);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, TransformVertices);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GoFullScreen);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, StopFullScreen);
HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GoFullScreen);
HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, StopFullScreen);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, IsFullScreen);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetDriverIndex);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, ChangeDriver);
Expand All @@ -863,7 +882,7 @@ struct RenderContextHook : public CKRenderContext {
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetWindowRect);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetHeight);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetWidth);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, Resize);
HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, Resize);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, SetViewRect);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetViewRect);
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetPixelFormat);
Expand Down Expand Up @@ -939,35 +958,64 @@ struct RenderContextHook : public CKRenderContext {
// HOOK_RENDER_CONTEXT_VIRTUAL_METHOD(rc, GetStereoParameters);

#undef HOOK_RENDER_CONTEXT_VIRTUAL_METHOD

#define CP_ADD_METHOD_HOOK(Name, Base, Offset) \
{ CP_FUNC_TARGET_PTR_NAME(Name) = utils::ForceReinterpretCast<CP_FUNC_TYPE_NAME(Name)>(Base, Offset); } \
if ((MH_CreateHook(*reinterpret_cast<LPVOID *>(&CP_FUNC_TARGET_PTR_NAME(Name)), \
*reinterpret_cast<LPVOID *>(&CP_FUNC_PTR_NAME(Name)), \
reinterpret_cast<LPVOID *>(&CP_FUNC_ORIG_PTR_NAME(Name))) != MH_OK || \
MH_EnableHook(*reinterpret_cast<LPVOID *>(&CP_FUNC_TARGET_PTR_NAME(Name))) != MH_OK)) \
return false;

void *base = utils::GetModuleBaseAddress("CK2_3D.dll");
assert(base != nullptr);

CP_ADD_METHOD_HOOK(UpdateProjection, base, 0x6C68D);
#undef CP_ADD_METHOD_HOOK

return true;
}

static void Unhook(CKRenderContext *rc) {
if (rc)
utils::SaveVTable<CP_CLASS_VTABLE_NAME(CKRenderContext)<CKRenderContext>>(rc, s_VTable);

#define CP_REMOVE_METHOD_HOOK(Name) \
MH_DisableHook(*reinterpret_cast<void **>(&CP_FUNC_TARGET_PTR_NAME(Name))); \
MH_RemoveHook(*reinterpret_cast<void **>(&CP_FUNC_TARGET_PTR_NAME(Name)));

CP_REMOVE_METHOD_HOOK(UpdateProjection);
#undef CP_REMOVE_METHOD_HOOK
}
};

bool RenderContextHook::s_DisableRender = false;
CP_CLASS_VTABLE_NAME(CKRenderContext)<CKRenderContext> RenderContextHook::s_VTable = {};
bool CP_HOOK_CLASS_NAME(CKRenderContext)::s_DisableRender = false;
bool CP_HOOK_CLASS_NAME(CKRenderContext)::s_EnableWidescreenFix = false;
CP_CLASS_VTABLE_NAME(CKRenderContext)<CKRenderContext> CP_HOOK_CLASS_NAME(CKRenderContext)::s_VTable = {};
CP_DEFINE_METHOD_PTRS(CKRenderContext, UpdateProjection)

namespace RenderHook {
void HookRenderManager(CKRenderManager *man) {
RenderManagerHook::Hook(man);
CP_HOOK_CLASS_NAME(CKRenderManager)::Hook(man);
}

void UnhookRenderManager(CKRenderManager *man) {
RenderManagerHook::Unhook(man);
CP_HOOK_CLASS_NAME(CKRenderManager)::Unhook(man);
}

void HookRenderContext(CKRenderContext *rc) {
RenderContextHook::Hook(rc);
CP_HOOK_CLASS_NAME(CKRenderContext)::Hook(rc);
}

void UnhookRenderContext(CKRenderContext *rc) {
RenderContextHook::Unhook(rc);
CP_HOOK_CLASS_NAME(CKRenderContext)::Unhook(rc);
}

void DisableRender(bool disable) {
RenderContextHook::s_DisableRender = disable;
CP_HOOK_CLASS_NAME(CKRenderContext)::s_DisableRender = disable;
}

void EnableWidescreenFix(bool enable) {
CP_HOOK_CLASS_NAME(CKRenderContext)::s_EnableWidescreenFix = enable;
}
}
1 change: 1 addition & 0 deletions src/RenderHook.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace RenderHook {
void UnhookRenderContext(CKRenderContext *rc);

void DisableRender(bool disable);
void EnableWidescreenFix(bool enable);
}

#endif // BML_RENDERHOOK_H

0 comments on commit 9961659

Please sign in to comment.