Skip to content

Commit

Permalink
headlight shadows option
Browse files Browse the repository at this point in the history
  • Loading branch information
ThirteenAG authored Sep 3, 2024
1 parent 300ccf4 commit ebe4a16
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 100 deletions.
6 changes: 3 additions & 3 deletions data/plugins/GTAIV.EFLC.FusionFix.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ OverrideCascadeRanges = 1 // increases shadow view distance
ShadowBlendRange = 0.3 // controls the size of the cascade blending regions | [0.0; 1.0]
ForceShadowFilter = 0 // 0 : shadow filter tied to definition | 1 : force 4 sample filter | 2 : force 16 sample filter
HighResolutionShadows = 0 // doubles cascaded shadowmap resolution, very GPU intensive
HighResolutionNightShadows = 0 // increases night shadows resolution, extremely GPU intensive

[SHADOWFILTERSHARP] // CE-like shadows
ShadowSoftness = 1.5 // controls shadow blur
Expand All @@ -18,9 +19,8 @@ ShadowBias = 5.0 // controls shadow bias, adjust ac
ShadowSoftness = 3.0 // controls shadow blur
ShadowBias = 8.0 // controls shadow bias, adjust according to softness

[NIGHTSHADOWS] // WARNING: enabling any of these options is not recommended
HeadlightShadows = 0 // 0: headlights do not cast shadows, like consoles | 1: forces all headlights to cast shadows, like PC
VehicleNightShadows = 0 // 1: enables shadows cast by vehicles from artificial lights, do not use with HeadlightShadows = 1
[NIGHTSHADOWS] // WARNING: enabling this option is not recommended
VehicleNightShadows = 0 // 1: with Headlight Shadows option, casts vehicle night shadows and disables player shadow(to avoid bugs), without Headlight Shadows enables shadows cast by vehicles from artificial lights

[FRAMELIMIT]
FrameLimitType = 2 // 1: realtime (thread-lock) | 2: accurate (sleep-yield), uses less resources
Expand Down
2 changes: 2 additions & 0 deletions data/update/TBoGT/common/data/frontend_menus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,7 @@
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_GRAPHICS_ANALYZER"
label="MO_ANALYZER" value="PREF_NULL" scaler="1"
Expand Down Expand Up @@ -1170,6 +1171,7 @@
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_GRAPHICS_ANALYZER"
label="MO_ANALYZER" value="PREF_NULL" scaler="1"
Expand Down
2 changes: 2 additions & 0 deletions data/update/TLAD/common/data/frontend_menus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,7 @@
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
Expand Down Expand Up @@ -1216,6 +1217,7 @@
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
Expand Down
2 changes: 2 additions & 0 deletions data/update/common/data/frontend_menus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,7 @@
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
Expand Down Expand Up @@ -814,6 +815,7 @@
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
Expand Down
1 change: 1 addition & 0 deletions source/comvars.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,7 @@ export int bMenuNeedsUpdate2 = 0;
export bool bEnableSnow = false;
export bool bEnableHall = false;
export bool bFixAutoExposure = true;
export bool bHeadlightShadows = false;

export inline LONG getWindowWidth()
{
Expand Down
113 changes: 78 additions & 35 deletions source/consoleshadows.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import comvars;

void* fnAE3DE0 = nullptr;
void* fnAE3310 = nullptr;
bool bHeadlightShadows = true;
bool bVehicleNightShadows = false;
int __cdecl sub_AE3DE0(int a1, int a2)
{
if (bVehicleNightShadows && !bHeadlightShadows)
if (bVehicleNightShadows)
injector::cstd<void(int, int, int, int, int)>::call(fnAE3310, a1, 0, 0, 0, a2);
return injector::cstd<int(int, int)>::call(fnAE3DE0, a1, a2);
}
Expand All @@ -29,6 +28,29 @@ void __stdcall grcSetRenderStateHook()
}
}

namespace CShadows
{
injector::hook_back<void(__cdecl*)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int)> hbStoreStaticShadow;

void __cdecl StoreStaticShadowPlayerDriving(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15)
{
if (!bHeadlightShadows)
{
a3 &= ~3;
a3 &= ~4;
}

return hbStoreStaticShadow.fun(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
}

void __cdecl StoreStaticShadowNPC(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15)
{
a3 &= ~3;
a3 &= ~4;

return hbStoreStaticShadow.fun(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
}
}
class ConsoleShadows
{
public:
Expand All @@ -37,7 +59,6 @@ public:
FusionFix::onInitEventAsync() += []()
{
CIniReader iniReader("");
bHeadlightShadows = iniReader.ReadInteger("NIGHTSHADOWS", "HeadlightShadows", 1) != 0;
bVehicleNightShadows = iniReader.ReadInteger("NIGHTSHADOWS", "VehicleNightShadows", 0) != 0;

// Render dynamic shadows casted by vehicles from point lights.
Expand All @@ -57,46 +78,68 @@ public:
sh_grcSetRendersState = safetyhook::create_inline(pattern.get_first(0), grcSetRenderStateHook);
}

// Enable player/ped shadows while in vehicles
if (bVehicleNightShadows && !bHeadlightShadows)
// Headlight shadows
{
auto pattern = hook::pattern("75 14 F6 86 ? ? ? ? ? 74 0B 80 7C 24 ? ? 0F 84 ? ? ? ? C6 44 24");
if (!pattern.empty())
auto pattern = hook::pattern("68 04 05 00 00 6A 02 6A 00");
if (!pattern.count(2).empty())
{
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
pattern = hook::pattern("75 12 8B 86 ? ? ? ? C1 E8 0B 25 ? ? ? ? 89 44 24 0C 85 D2");
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(0).get<void*>(9), CShadows::StoreStaticShadowPlayerDriving).get();
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(1).get<void*>(9), CShadows::StoreStaticShadowPlayerDriving).get();
}
else

pattern = hook::pattern("68 04 01 00 00 6A 02 6A 00");
if (!pattern.count(2).empty())
{
pattern = hook::pattern("75 17 F6 86 ? ? ? ? ? 74 0E 80 7C 24 ? ? 0F 84");
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
pattern = hook::pattern("75 0F 8B 86 ? ? ? ? C1 E8 0B 24 01 88 44 24 0E");
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(0).get<void*>(9), CShadows::StoreStaticShadowNPC).get();
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(1).get<void*>(9), CShadows::StoreStaticShadowNPC).get();
}

FusionFixSettings.SetCallback("PREF_HEADLIGHTSHADOWS", [](int32_t value)
{
bHeadlightShadows = value;
});
bHeadlightShadows = FusionFixSettings("PREF_HEADLIGHTSHADOWS");

}

// Disable headlight shadows to avoid flickering/self-shadowing.
if (!bHeadlightShadows)
{
auto pattern = hook::pattern("74 76 FF 75 30 FF 75 2C FF 75 28 83 EC 0C 80 7D 38 00");
pattern = hook::pattern("E8 ? ? ? ? 85 C0 74 29 6A 00");
if (!pattern.empty())
{
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
pattern = hook::pattern("68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 8B E5 5D C3 68");
injector::WriteMemory(pattern.count(2).get(1).get<void*>(1), 0x100, true);
pattern = hook::pattern("8B E5 5D C3 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 8B E5 5D C3");
injector::WriteMemory(pattern.count(2).get(1).get<void*>(5), 0x100, true);
}
else
{
pattern = hook::pattern("0F 84 ? ? ? ? 80 7D 28 00 74 4C 8B 45 20 8B 0D");
injector::WriteMemory<uint16_t>(pattern.get_first(0), 0xE990, true);
pattern = hook::pattern("68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 5B 8B E5 5D C3 8B 15");
injector::WriteMemory(pattern.get_first(1), 0x100, true);
pattern = hook::pattern("8D 44 24 50 50 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 5B 8B E5 5D C3");
injector::WriteMemory(pattern.get_first(6), 0x100, true);
static auto getLocalPlayerPed = (int (*)())injector::GetBranchDestination(pattern.get_first(0)).as_int();
static auto FindPlayerCar = (int (*)())injector::GetBranchDestination(pattern.get_first(11)).as_int();

static auto loc_AE3867 = (uintptr_t)hook::get_pattern("8B 74 24 14 FF 44 24 10");
static auto loc_AE376B = (uintptr_t)hook::get_pattern("85 D2 75 4C 0F B6 46 62 50");
static auto loc_AE374F = (uintptr_t)hook::get_pattern("C6 44 24 ? ? 83 F8 04 75 12");

pattern = hook::pattern("83 F8 03 75 14 F6 86");
struct ShadowsHook
{
void operator()(injector::reg_pack& regs)
{
if (bHeadlightShadows && bVehicleNightShadows)
{
auto car = FindPlayerCar();

// Disable player/car shadows
if (regs.esi && (regs.esi == car || (regs.esi == getLocalPlayerPed() && car && *(uint32_t*)(car + 0xFA0))))
{
*(uintptr_t*)(regs.esp - 4) = loc_AE3867;
return;
}
}

// Enable player/ped shadows while in vehicles
if (bHeadlightShadows && bVehicleNightShadows && (regs.eax == 3 || regs.eax == 4))
{
*(uintptr_t*)(regs.esp - 4) = loc_AE376B;
return;
}

if ((*(uint8_t*)(regs.esi + 620) & 4) == 0)
{
*(uintptr_t*)(regs.esp - 4) = loc_AE374F;
}
}
}; injector::MakeInline<ShadowsHook>(pattern.get_first(0), pattern.get_first(14));
}
}
};
Expand Down
14 changes: 12 additions & 2 deletions source/extrainfo.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,21 @@ public:
if (imgNum >= imgArrSize) extra += FF_WARN1[0] ? FF_WARN1 : L"; ~r~WARNING: 255 IMG limit exceeded, will cause streaming issues.";

static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
if (LamppostShadows->get())
if (LamppostShadows->get() || bHeadlightShadows)
{
extra += L"~n~";
extra += L" ";
auto FF_WARN2 = CText::getText("FF_WARN2");
auto FF_WARN2 = std::wstring(CText::getText("FF_WARN2"));
auto HeadlightShadow = CText::getText("HeadlightShadow");

if (bHeadlightShadows)
{
auto pos = FF_WARN2.find(L": ");
if (pos != std::wstring::npos) {
FF_WARN2.replace(pos, 2, L": " + std::wstring(HeadlightShadow) + L" / ");
}
}

if (FF_WARN2[0])
extra += FF_WARN2;
else
Expand Down
56 changes: 0 additions & 56 deletions source/fixes.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -56,32 +56,6 @@ public:
return r;
}

static inline SafetyHookInline shsub_925DB0{};
static int __cdecl sub_925DB0(int a1, int a2, int flags)
{
static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
if (!LamppostShadows->get())
{
if (!Natives::IsInteriorScene())
return -1;
}

return shsub_925DB0.ccall<int>(a1, a2, flags);
}

static inline SafetyHookInline shsub_D77A00{};
static void __fastcall sub_D77A00(void* _this, void* edx)
{
static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
if (!LamppostShadows->get())
{
if (!Natives::IsInteriorScene())
return;
}

return shsub_D77A00.fastcall(_this, edx);
}

Fixes()
{
FusionFix::onInitEventAsync() += []()
Expand Down Expand Up @@ -436,36 +410,6 @@ public:
if (!pattern.empty())
injector::MakeNOP(pattern.get_first(0), 8, true);
}

// Lampposts shadows workaround
{
auto pattern = hook::pattern("80 3D ? ? ? ? ? 75 04 83 C8 FF");
shsub_925DB0 = safetyhook::create_inline(pattern.get_first(), sub_925DB0);

pattern = find_pattern("83 EC 3C 80 3D ? ? ? ? ? 56 8B F1", "83 EC 3C 53 33 DB");
shsub_D77A00 = safetyhook::create_inline(pattern.get_first(0), sub_D77A00);

pattern = find_pattern("8B 55 20 F6 C1 06");
if (!pattern.empty())
{
static auto ShadowsHook2 = safetyhook::create_mid(pattern.get_first(0), [](SafetyHookContext& regs)
{
static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
if (!LamppostShadows->get())
{
if (Natives::IsInteriorScene())
{
if ((*(uint32_t*)(regs.edi + 0x4C) & 0x8000000) != 0) // new flag to detect affected lampposts
{
regs.ecx &= ~3;
regs.ecx &= ~4;
*(uint32_t*)(regs.esp + 0x18) = regs.ecx;
}
}
}
});
}
}

// Render LOD lights during cutscenes (console behavior)
{
Expand Down
Loading

0 comments on commit ebe4a16

Please sign in to comment.