Skip to content

Commit

Permalink
the saboteur fov fix
Browse files Browse the repository at this point in the history
  • Loading branch information
ThirteenAG committed Nov 9, 2023
1 parent f0abc77 commit d6473ff
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 2 deletions.
10 changes: 10 additions & 0 deletions .github/docs/thesaboteur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
![thesaboteur](https://thirteenag.github.io/screens/thesaboteur/main2.jpg)

![](https://habrastorage.org/webt/ow/yy/mg/owyymgpibfqzfbwyf_iqoiqrede.png) Fixed Field of View

![](https://habrastorage.org/webt/d_/eg/ym/d_egymd6w_tem2erocab-e9ikna.png) Added an option to make windowed mode borderless

Installation:
Download and extract the archive to the game directory, where the exe is located.

[Website](https://thirteenag.github.io/wfp#thesaboteur) | [Source](https://github.com/ThirteenAG/WidescreenFixesPack/blob/master/source/TheSaboteur.FusionFix/dllmain.cpp) | [Default INI File](https://github.com/ThirteenAG/WidescreenFixesPack/blob/master/data/TheSaboteur.FusionFix/plugins/TheSaboteur.FusionFix.ini)
8 changes: 8 additions & 0 deletions .github/workflows/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,14 @@ jobs:
tag: driv3r
artifacts: data/Archives/Driv3r.WidescreenFix.zip

- name: The Saboteur Fusion Fix
uses: ./.github/workflows/release_tag
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_list: ${{ format('{0},{1}', github.event.inputs.tag_list, inputs.tag_list) }}
tag: thesaboteur
artifacts: data/Archives/TheSaboteur.FusionFix.zip

- name: The Suffering Widescreen Fix
uses: ./.github/workflows/release_tag
with:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ on:
- thaw
- thegodfather
- thematrixpathofneo
- thesaboteur
- thesuffering
- thewarriors
- thps2
Expand Down Expand Up @@ -180,6 +181,7 @@ env:
thaw: "/t:TonyHawksAmericanWasteland_WidescreenFix"
thegodfather: "/t:TheGodfather_WidescreenFix"
thematrixpathofneo: "/t:TheMatrixPathOfNeo_WidescreenFix"
thesaboteur: "/t:TheSaboteur_FusionFix"
thesuffering: "/t:TheSuffering_WidescreenFix"
thewarriors: "/t:TheWarriors_PPSSPP_FusionMod"
thps2: "/t:TonyHawksProSkater2_WidescreenFix"
Expand Down
1 change: 1 addition & 0 deletions data/TheSaboteur.FusionFix/dinput8.ual
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
loadfromscriptsonly
3 changes: 3 additions & 0 deletions data/TheSaboteur.FusionFix/scripts/TheSaboteur.FusionFix.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[MAIN]
FixFOV = 1
BorderlessWindowed = 1
2 changes: 0 additions & 2 deletions includes/LED/LEDEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
#include <chrono>
#include <vector>
#include <algorithm>
#include <CommCtrl.h>
#pragma comment(lib, "Comctl32.lib")

class LEDEffects
{
Expand Down
2 changes: 2 additions & 0 deletions premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,8 @@ project "TheMatrixPathOfNeo.WidescreenFix"
setpaths("Z:/WFP/Games/The Matrix - Path Of Neo/", "Matrix3.exe")
project "ThePunisher.WidescreenFix"
setpaths("Z:/WFP/Games/The Punisher/", "pun.exe")
project "TheSaboteur.FusionFix"
setpaths("Z:/WFP/Games/The Saboteur/", "Saboteur.exe")
project "TheSuffering.WidescreenFix"
setpaths("Z:/WFP/Games/The Suffering/The Suffering/", "suffering.exe")
project "TheWarriors.PPSSPP.FusionMod"
Expand Down
123 changes: 123 additions & 0 deletions source/TheSaboteur.FusionFix/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include "stdafx.h"

struct PblVector4
{
float x;
float y;
float z;
float w;
};

struct PblMatrix4x4
{
PblVector4 _m[4];
};

struct OdinCamera
{
bool m_bOrthographic;
PblMatrix4x4 m_ViewMatrix;
PblMatrix4x4 m_ViewMatrixInverse;
PblMatrix4x4 m_ProjMatrix;
PblMatrix4x4 m_ProjMatrixInverse;
unsigned int m_Dirty;
float m_NearPlane;
float m_FarPlane;
float m_TanHalfFOVWidth;
float m_TanHalfFOVHeight;

static void __fastcall SetFOV(OdinCamera* OdinCamera, void* edx, float a_FovX, float a_AspectRatio)
{
// too high fov breaks rendering (sky and objects start to disappear)
auto fAspectRatioDiff = std::clamp((1.0f / a_AspectRatio) / (4.0f / 3.0f), 0.0f, 2.1f); // 2.1 seems safe before that happens
auto a_FovXa = a_FovX * 0.5f;
auto a_FovXb = tan(a_FovXa);
OdinCamera->m_Dirty |= 3u;
OdinCamera->m_bOrthographic = 0;
OdinCamera->m_TanHalfFOVWidth = a_FovXb * fAspectRatioDiff;
OdinCamera->m_TanHalfFOVHeight = a_FovXb * a_AspectRatio * fAspectRatioDiff;
}

static void __fastcall SetPerspective(OdinCamera* OdinCamera, void* edx, float a_NearPlane, float a_FarPlane, float a_FovX, float a_AspectRatio)
{
auto a_FovXa = a_FovX * 0.5f;
auto a_FovXb = tan(a_FovXa);
OdinCamera->m_Dirty |= 3u;
OdinCamera->m_bOrthographic = 0;
OdinCamera->m_NearPlane = a_NearPlane;
OdinCamera->m_FarPlane = a_FarPlane;
OdinCamera->m_TanHalfFOVWidth = a_FovXb;
OdinCamera->m_TanHalfFOVHeight = a_FovXb * a_AspectRatio;
}

static float __fastcall GetAspectRatio(OdinCamera* OdinCamera, void* edx)
{
return OdinCamera->m_TanHalfFOVHeight / OdinCamera->m_TanHalfFOVWidth;
}
};

void Init()
{
WFP::onInitEventAsync() += []()
{
CIniReader iniReader("");
auto bFixFOV = iniReader.ReadInteger("MAIN", "FixFOV", 1) != 0;
auto bBorderlessWindowed = iniReader.ReadInteger("MAIN", "BorderlessWindowed", 1) != 0;

if (bFixFOV)
{
auto pattern = hook::pattern("D9 44 24 04 56 DC 0D ? ? ? ? 8B F1 D9 5C 24 08");
injector::MakeJMP(pattern.get_first(0), OdinCamera::SetFOV, true);

//auto pattern = hook::pattern("D9 44 24 0C 56 DC 0D ? ? ? ? 8B F1 D9 5C 24 10 D9 44 24 10 E8 ? ? ? ? D9 5C 24 10 D9 44 24 10 83 8E");
//injector::MakeJMP(pattern.get_first(0), OdinCamera::SetPerspective, true);

//pattern = hook::pattern("51 D9 81 ? ? ? ? D8 B1");
//injector::MakeJMP(pattern.get_first(0), OdinCamera::GetAspectRatio, true);
}

if (bBorderlessWindowed)
{
IATHook::Replace(GetModuleHandleA(NULL), "USER32.DLL",
std::forward_as_tuple("CreateWindowExA", WindowedModeWrapper::CreateWindowExA_Hook),
std::forward_as_tuple("CreateWindowExW", WindowedModeWrapper::CreateWindowExW_Hook),
std::forward_as_tuple("SetWindowLongA", WindowedModeWrapper::SetWindowLongA_Hook),
std::forward_as_tuple("SetWindowLongW", WindowedModeWrapper::SetWindowLongW_Hook),
std::forward_as_tuple("AdjustWindowRect", WindowedModeWrapper::AdjustWindowRect_Hook),
std::forward_as_tuple("SetWindowPos", WindowedModeWrapper::SetWindowPos_Hook)
);
}
};

static auto futures = WFP::onInitEventAsync().executeAllAsync();

WFP::onGameInitEvent() += []() //todo: add onGameInitEvent hook
{
for (auto& f : futures.get())
f.wait();
futures.get().clear();
};

WFP::onInitEvent().executeAll();
}

CEXP void InitializeASI()
{
std::call_once(CallbackHandler::flag, []()
{
CallbackHandler::RegisterCallback(Init, hook::pattern("56 68 ? ? ? ? 68 ? ? ? ? 8B F1 6A 19"));
});
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
if (!IsUALPresent()) { InitializeASI(); }
}
else if (reason == DLL_PROCESS_DETACH)
{

}
return TRUE;
}

0 comments on commit d6473ff

Please sign in to comment.