Skip to content

Commit ebe4a16

Browse files
authored
headlight shadows option
1 parent 300ccf4 commit ebe4a16

File tree

18 files changed

+185
-100
lines changed

18 files changed

+185
-100
lines changed

data/plugins/GTAIV.EFLC.FusionFix.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ OverrideCascadeRanges = 1 // increases shadow view distance
99
ShadowBlendRange = 0.3 // controls the size of the cascade blending regions | [0.0; 1.0]
1010
ForceShadowFilter = 0 // 0 : shadow filter tied to definition | 1 : force 4 sample filter | 2 : force 16 sample filter
1111
HighResolutionShadows = 0 // doubles cascaded shadowmap resolution, very GPU intensive
12+
HighResolutionNightShadows = 0 // increases night shadows resolution, extremely GPU intensive
1213

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

21-
[NIGHTSHADOWS] // WARNING: enabling any of these options is not recommended
22-
HeadlightShadows = 0 // 0: headlights do not cast shadows, like consoles | 1: forces all headlights to cast shadows, like PC
23-
VehicleNightShadows = 0 // 1: enables shadows cast by vehicles from artificial lights, do not use with HeadlightShadows = 1
22+
[NIGHTSHADOWS] // WARNING: enabling this option is not recommended
23+
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
2424

2525
[FRAMELIMIT]
2626
FrameLimitType = 2 // 1: realtime (thread-lock) | 2: accurate (sleep-yield), uses less resources

data/update/TBoGT/common/data/frontend_menus.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,7 @@
11161116
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
11171117
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
11181118
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
1119+
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
11191120
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
11201121
<optionspc action="MENUOPT_GRAPHICS_ANALYZER"
11211122
label="MO_ANALYZER" value="PREF_NULL" scaler="1"
@@ -1170,6 +1171,7 @@
11701171
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
11711172
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
11721173
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
1174+
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
11731175
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
11741176
<optionspc action="MENUOPT_GRAPHICS_ANALYZER"
11751177
label="MO_ANALYZER" value="PREF_NULL" scaler="1"

data/update/TLAD/common/data/frontend_menus.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,7 @@
11891189
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
11901190
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
11911191
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
1192+
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
11921193
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
11931194
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
11941195
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
@@ -1216,6 +1217,7 @@
12161217
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
12171218
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
12181219
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
1220+
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
12191221
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
12201222
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
12211223
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />

data/update/common/data/frontend_menus.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@
786786
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
787787
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
788788
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
789+
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
789790
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
790791
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
791792
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
@@ -814,6 +815,7 @@
814815
<optionspc action="MENUOPT_ADJUST" label="FPS Limiter" value="PREF_FPS_LIMIT_PRESET" scaler="15" displayValue="MENU_DISPLAY_FRAMELIMIT" />
815816
<optionspc action="MENUOPT_ADJUST" label="MO_FOV" value="PREF_EPISODIC_RACECLASS_RACE_3" scaler="10" displayValue="MENU_DISPLAY_SLIDERBAR" />
816817
<optionspc action="MENUOPT_ADJUST" label="LamppostShadows" value="PREF_LAMPPOSTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
818+
<optionspc action="MENUOPT_ADJUST" label="HeadlightShadow" value="PREF_HEADLIGHTSHADOWS" scaler="2" displayValue="MENU_DISPLAY_ON_OFF" />
817819
<options action="MENUOPT_NONE" label="" value="PREF_NULL" scaler="0" displayValue="MENU_DISPLAY_NONE" />
818820
<optionspc action="MENUOPT_GRAPHICS_ANALYZER" label="MO_ANALYZER" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />
819821
<optionspc action="MENUOPT_BENCHMARK" label="MO_BENCHMARK" value="PREF_NULL" scaler="1" displayValue="MENU_DISPLAY_NONE" />

source/comvars.ixx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,7 @@ export int bMenuNeedsUpdate2 = 0;
10421042
export bool bEnableSnow = false;
10431043
export bool bEnableHall = false;
10441044
export bool bFixAutoExposure = true;
1045+
export bool bHeadlightShadows = false;
10451046

10461047
export inline LONG getWindowWidth()
10471048
{

source/consoleshadows.ixx

Lines changed: 78 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ import comvars;
1010

1111
void* fnAE3DE0 = nullptr;
1212
void* fnAE3310 = nullptr;
13-
bool bHeadlightShadows = true;
1413
bool bVehicleNightShadows = false;
1514
int __cdecl sub_AE3DE0(int a1, int a2)
1615
{
17-
if (bVehicleNightShadows && !bHeadlightShadows)
16+
if (bVehicleNightShadows)
1817
injector::cstd<void(int, int, int, int, int)>::call(fnAE3310, a1, 0, 0, 0, a2);
1918
return injector::cstd<int(int, int)>::call(fnAE3DE0, a1, a2);
2019
}
@@ -29,6 +28,29 @@ void __stdcall grcSetRenderStateHook()
2928
}
3029
}
3130

31+
namespace CShadows
32+
{
33+
injector::hook_back<void(__cdecl*)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int)> hbStoreStaticShadow;
34+
35+
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)
36+
{
37+
if (!bHeadlightShadows)
38+
{
39+
a3 &= ~3;
40+
a3 &= ~4;
41+
}
42+
43+
return hbStoreStaticShadow.fun(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
44+
}
45+
46+
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)
47+
{
48+
a3 &= ~3;
49+
a3 &= ~4;
50+
51+
return hbStoreStaticShadow.fun(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
52+
}
53+
}
3254
class ConsoleShadows
3355
{
3456
public:
@@ -37,7 +59,6 @@ public:
3759
FusionFix::onInitEventAsync() += []()
3860
{
3961
CIniReader iniReader("");
40-
bHeadlightShadows = iniReader.ReadInteger("NIGHTSHADOWS", "HeadlightShadows", 1) != 0;
4162
bVehicleNightShadows = iniReader.ReadInteger("NIGHTSHADOWS", "VehicleNightShadows", 0) != 0;
4263

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

60-
// Enable player/ped shadows while in vehicles
61-
if (bVehicleNightShadows && !bHeadlightShadows)
81+
// Headlight shadows
6282
{
63-
auto pattern = hook::pattern("75 14 F6 86 ? ? ? ? ? 74 0B 80 7C 24 ? ? 0F 84 ? ? ? ? C6 44 24");
64-
if (!pattern.empty())
83+
auto pattern = hook::pattern("68 04 05 00 00 6A 02 6A 00");
84+
if (!pattern.count(2).empty())
6585
{
66-
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
67-
pattern = hook::pattern("75 12 8B 86 ? ? ? ? C1 E8 0B 25 ? ? ? ? 89 44 24 0C 85 D2");
68-
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
86+
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(0).get<void*>(9), CShadows::StoreStaticShadowPlayerDriving).get();
87+
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(1).get<void*>(9), CShadows::StoreStaticShadowPlayerDriving).get();
6988
}
70-
else
89+
90+
pattern = hook::pattern("68 04 01 00 00 6A 02 6A 00");
91+
if (!pattern.count(2).empty())
7192
{
72-
pattern = hook::pattern("75 17 F6 86 ? ? ? ? ? 74 0E 80 7C 24 ? ? 0F 84");
73-
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
74-
pattern = hook::pattern("75 0F 8B 86 ? ? ? ? C1 E8 0B 24 01 88 44 24 0E");
75-
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
93+
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(0).get<void*>(9), CShadows::StoreStaticShadowNPC).get();
94+
CShadows::hbStoreStaticShadow.fun = injector::MakeCALL(pattern.count(2).get(1).get<void*>(9), CShadows::StoreStaticShadowNPC).get();
7695
}
96+
97+
FusionFixSettings.SetCallback("PREF_HEADLIGHTSHADOWS", [](int32_t value)
98+
{
99+
bHeadlightShadows = value;
100+
});
101+
bHeadlightShadows = FusionFixSettings("PREF_HEADLIGHTSHADOWS");
77102

78-
}
79-
80-
// Disable headlight shadows to avoid flickering/self-shadowing.
81-
if (!bHeadlightShadows)
82-
{
83-
auto pattern = hook::pattern("74 76 FF 75 30 FF 75 2C FF 75 28 83 EC 0C 80 7D 38 00");
103+
pattern = hook::pattern("E8 ? ? ? ? 85 C0 74 29 6A 00");
84104
if (!pattern.empty())
85105
{
86-
injector::WriteMemory<uint8_t>(pattern.get_first(0), 0xEB, true);
87-
pattern = hook::pattern("68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 8B E5 5D C3 68");
88-
injector::WriteMemory(pattern.count(2).get(1).get<void*>(1), 0x100, true);
89-
pattern = hook::pattern("8B E5 5D C3 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 8B E5 5D C3");
90-
injector::WriteMemory(pattern.count(2).get(1).get<void*>(5), 0x100, true);
91-
}
92-
else
93-
{
94-
pattern = hook::pattern("0F 84 ? ? ? ? 80 7D 28 00 74 4C 8B 45 20 8B 0D");
95-
injector::WriteMemory<uint16_t>(pattern.get_first(0), 0xE990, true);
96-
pattern = hook::pattern("68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 5B 8B E5 5D C3 8B 15");
97-
injector::WriteMemory(pattern.get_first(1), 0x100, true);
98-
pattern = hook::pattern("8D 44 24 50 50 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 5B 8B E5 5D C3");
99-
injector::WriteMemory(pattern.get_first(6), 0x100, true);
106+
static auto getLocalPlayerPed = (int (*)())injector::GetBranchDestination(pattern.get_first(0)).as_int();
107+
static auto FindPlayerCar = (int (*)())injector::GetBranchDestination(pattern.get_first(11)).as_int();
108+
109+
static auto loc_AE3867 = (uintptr_t)hook::get_pattern("8B 74 24 14 FF 44 24 10");
110+
static auto loc_AE376B = (uintptr_t)hook::get_pattern("85 D2 75 4C 0F B6 46 62 50");
111+
static auto loc_AE374F = (uintptr_t)hook::get_pattern("C6 44 24 ? ? 83 F8 04 75 12");
112+
113+
pattern = hook::pattern("83 F8 03 75 14 F6 86");
114+
struct ShadowsHook
115+
{
116+
void operator()(injector::reg_pack& regs)
117+
{
118+
if (bHeadlightShadows && bVehicleNightShadows)
119+
{
120+
auto car = FindPlayerCar();
121+
122+
// Disable player/car shadows
123+
if (regs.esi && (regs.esi == car || (regs.esi == getLocalPlayerPed() && car && *(uint32_t*)(car + 0xFA0))))
124+
{
125+
*(uintptr_t*)(regs.esp - 4) = loc_AE3867;
126+
return;
127+
}
128+
}
129+
130+
// Enable player/ped shadows while in vehicles
131+
if (bHeadlightShadows && bVehicleNightShadows && (regs.eax == 3 || regs.eax == 4))
132+
{
133+
*(uintptr_t*)(regs.esp - 4) = loc_AE376B;
134+
return;
135+
}
136+
137+
if ((*(uint8_t*)(regs.esi + 620) & 4) == 0)
138+
{
139+
*(uintptr_t*)(regs.esp - 4) = loc_AE374F;
140+
}
141+
}
142+
}; injector::MakeInline<ShadowsHook>(pattern.get_first(0), pattern.get_first(14));
100143
}
101144
}
102145
};

source/extrainfo.ixx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,21 @@ public:
4949
if (imgNum >= imgArrSize) extra += FF_WARN1[0] ? FF_WARN1 : L"; ~r~WARNING: 255 IMG limit exceeded, will cause streaming issues.";
5050

5151
static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
52-
if (LamppostShadows->get())
52+
if (LamppostShadows->get() || bHeadlightShadows)
5353
{
5454
extra += L"~n~";
5555
extra += L" ";
56-
auto FF_WARN2 = CText::getText("FF_WARN2");
56+
auto FF_WARN2 = std::wstring(CText::getText("FF_WARN2"));
57+
auto HeadlightShadow = CText::getText("HeadlightShadow");
58+
59+
if (bHeadlightShadows)
60+
{
61+
auto pos = FF_WARN2.find(L": ");
62+
if (pos != std::wstring::npos) {
63+
FF_WARN2.replace(pos, 2, L": " + std::wstring(HeadlightShadow) + L" / ");
64+
}
65+
}
66+
5767
if (FF_WARN2[0])
5868
extra += FF_WARN2;
5969
else

source/fixes.ixx

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -56,32 +56,6 @@ public:
5656
return r;
5757
}
5858

59-
static inline SafetyHookInline shsub_925DB0{};
60-
static int __cdecl sub_925DB0(int a1, int a2, int flags)
61-
{
62-
static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
63-
if (!LamppostShadows->get())
64-
{
65-
if (!Natives::IsInteriorScene())
66-
return -1;
67-
}
68-
69-
return shsub_925DB0.ccall<int>(a1, a2, flags);
70-
}
71-
72-
static inline SafetyHookInline shsub_D77A00{};
73-
static void __fastcall sub_D77A00(void* _this, void* edx)
74-
{
75-
static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
76-
if (!LamppostShadows->get())
77-
{
78-
if (!Natives::IsInteriorScene())
79-
return;
80-
}
81-
82-
return shsub_D77A00.fastcall(_this, edx);
83-
}
84-
8559
Fixes()
8660
{
8761
FusionFix::onInitEventAsync() += []()
@@ -436,36 +410,6 @@ public:
436410
if (!pattern.empty())
437411
injector::MakeNOP(pattern.get_first(0), 8, true);
438412
}
439-
440-
// Lampposts shadows workaround
441-
{
442-
auto pattern = hook::pattern("80 3D ? ? ? ? ? 75 04 83 C8 FF");
443-
shsub_925DB0 = safetyhook::create_inline(pattern.get_first(), sub_925DB0);
444-
445-
pattern = find_pattern("83 EC 3C 80 3D ? ? ? ? ? 56 8B F1", "83 EC 3C 53 33 DB");
446-
shsub_D77A00 = safetyhook::create_inline(pattern.get_first(0), sub_D77A00);
447-
448-
pattern = find_pattern("8B 55 20 F6 C1 06");
449-
if (!pattern.empty())
450-
{
451-
static auto ShadowsHook2 = safetyhook::create_mid(pattern.get_first(0), [](SafetyHookContext& regs)
452-
{
453-
static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS");
454-
if (!LamppostShadows->get())
455-
{
456-
if (Natives::IsInteriorScene())
457-
{
458-
if ((*(uint32_t*)(regs.edi + 0x4C) & 0x8000000) != 0) // new flag to detect affected lampposts
459-
{
460-
regs.ecx &= ~3;
461-
regs.ecx &= ~4;
462-
*(uint32_t*)(regs.esp + 0x18) = regs.ecx;
463-
}
464-
}
465-
}
466-
});
467-
}
468-
}
469413

470414
// Render LOD lights during cutscenes (console behavior)
471415
{

0 commit comments

Comments
 (0)