1- #include " InteriorSunShadows .h"
1+ #include " InteriorSun .h"
22#include " State.h"
33
44#include < numbers>
55
66NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT (
7- InteriorSunShadows::Settings,
8- ForceDoubleSidedRendering)
7+ InteriorSun::Settings,
8+ ForceDoubleSidedRendering,
9+ InteriorShadowDistance)
910
10- void InteriorSunShadows ::DrawSettings()
11+ void InteriorSun ::DrawSettings()
1112{
1213 ImGui::Checkbox (" Force Double-Sided Rendering" , &settings.ForceDoubleSidedRendering );
1314 if (auto _tt = Util::HoverTooltipWrapper ()) {
1415 ImGui::Text (
1516 " Disables backface culling during sun shadowmap rendering in interiors. "
1617 " Will prevent most light leaking through unmasked/unprepared interiors at a small performance cost. " );
1718 }
19+ if (ImGui::SliderFloat (" Interior Shadow Distance" , &settings.InteriorShadowDistance , 1000 .0f , 8000 .0f )) {
20+ *gInteriorShadowDistance = settings.InteriorShadowDistance ;
21+ SetShadowDistance (globals::game::tes && globals::game::tes->interiorCell );
22+ }
23+ if (auto _tt = Util::HoverTooltipWrapper ()) {
24+ ImGui::Text (
25+ " Sets the distance shadows are rendered at in interiors. "
26+ " Lower values provide higher quality shadows and improved performance but may cause distant interior spaces to light up incorrectly. " );
27+ }
1828}
1929
20- void InteriorSunShadows ::LoadSettings (json& o_json)
30+ void InteriorSun ::LoadSettings (json& o_json)
2131{
2232 settings = o_json;
2333}
2434
25- void InteriorSunShadows ::SaveSettings (json& o_json)
35+ void InteriorSun ::SaveSettings (json& o_json)
2636{
2737 o_json = settings;
2838}
2939
30- void InteriorSunShadows ::RestoreDefaultSettings ()
40+ void InteriorSun ::RestoreDefaultSettings ()
3141{
3242 settings = {};
3343}
3444
35- void InteriorSunShadows ::PostPostLoad ()
45+ void InteriorSun ::PostPostLoad ()
3646{
3747 // Hooks and patch to enable directional lighting for interiors
3848 stl::write_thunk_call<GetWorldSpace>(REL::RelocationID (35562 , 36561 ).address () + REL::Relocate (0x399 , 0x37D , 0x639 ));
@@ -48,6 +58,7 @@ void InteriorSunShadows::PostPostLoad()
4858 REL::safe_fill (REL::RelocationID (38900 , 39946 ).address () + REL::Relocate (0x2CA , 0x22B ), REL::NOP, REL::Module::IsAE () ? 6 : 2 );
4959
5060 gShadowDistance = reinterpret_cast <float *>(REL::RelocationID (528314 , 415263 ).address ());
61+ gInteriorShadowDistance = reinterpret_cast <float *>(REL::RelocationID (513755 , 391724 ).address ());
5162
5263 // Patches BSShadowDirectionalLight::SetFrameCamera to read the correct shadow distance value in interior cells
5364 const std::uintptr_t address = REL::RelocationID (101499 , 108496 ).address () + REL::Relocate (0xD62 , 0xE6C , 0xE72 );
@@ -56,41 +67,41 @@ void InteriorSunShadows::PostPostLoad()
5667
5768 rasterStateCullMode = globals::game::isVR ? &globals::game::shadowState->GetVRRuntimeData ().rasterStateCullMode : &globals::game::shadowState->GetRuntimeData ().rasterStateCullMode ;
5869
59- logger::info (" [Interior Sun Shadows ] Installed hooks" );
70+ logger::info (" [Interior Sun] Installed hooks" );
6071}
6172
62- void InteriorSunShadows ::EarlyPrepass ()
73+ void InteriorSun ::EarlyPrepass ()
6374{
6475 isInteriorWithSun = IsInteriorWithSun (globals::game::tes->interiorCell );
6576}
6677
67- inline bool InteriorSunShadows ::IsInteriorWithSun (const RE::TESObjectCELL* cell)
78+ inline bool InteriorSun ::IsInteriorWithSun (const RE::TESObjectCELL* cell)
6879{
6980 return cell && cell->cellFlags .all (RE::TESObjectCELL::Flag::kIsInteriorCell , RE::TESObjectCELL::Flag::kShowSky , RE::TESObjectCELL::Flag::kUseSkyLighting , static_cast <RE::TESObjectCELL::Flag>(CellFlagExt::kSunlightShadows ));
7081}
7182
72- RE::TESWorldSpace* InteriorSunShadows ::GetWorldSpace::thunk (RE::TES* tes)
83+ RE::TESWorldSpace* InteriorSun ::GetWorldSpace::thunk (RE::TES* tes)
7384{
7485 if (const auto cell = tes->interiorCell )
75- return IsInteriorWithSun (cell) ? enableInteriorSunShadows : disableInteriorSunShadows ;
86+ return IsInteriorWithSun (cell) ? enableInteriorSun : disableInteriorSun ;
7687 return func (tes);
7788}
7889
79- RE::TESWorldSpace* InteriorSunShadows::enableInteriorSunShadows = [] {
90+ RE::TESWorldSpace* InteriorSun::enableInteriorSun = [] {
8091 alignas (RE::TESWorldSpace) static char buffer[sizeof (RE::TESWorldSpace)]{};
8192 return reinterpret_cast <RE::TESWorldSpace*>(buffer);
8293}();
8394
84- RE::TESWorldSpace* InteriorSunShadows::disableInteriorSunShadows = [] {
95+ RE::TESWorldSpace* InteriorSun::disableInteriorSun = [] {
8596 alignas (RE::TESWorldSpace) static char buffer[sizeof (RE::TESWorldSpace)] = {};
8697 const auto noShadows = reinterpret_cast <RE::TESWorldSpace*>(buffer);
8798 noShadows->flags .set (RE::TESWorldSpace::Flag::kNoSky , RE::TESWorldSpace::Flag::kFixedDimensions );
8899 return noShadows;
89100}();
90101
91- void InteriorSunShadows ::DirShadowLightCulling::thunk (RE::BSShadowDirectionalLight* dirLight, RE::BSTArray<RE::BSTArray<RE::NiPointer<RE::NiAVObject>>>& jobArrays, RE::BSTArray<RE::NiPointer<RE::NiAVObject>>& nodes)
102+ void InteriorSun ::DirShadowLightCulling::thunk (RE::BSShadowDirectionalLight* dirLight, RE::BSTArray<RE::BSTArray<RE::NiPointer<RE::NiAVObject>>>& jobArrays, RE::BSTArray<RE::NiPointer<RE::NiAVObject>>& nodes)
92103{
93- auto & singleton = globals::features::interiorSunShadows ;
104+ auto & singleton = globals::features::interiorSun ;
94105 const auto cell = globals::game::tes->interiorCell ;
95106 auto * passedJobArrays = &jobArrays;
96107
@@ -111,7 +122,7 @@ void InteriorSunShadows::DirShadowLightCulling::thunk(RE::BSShadowDirectionalLig
111122 func (dirLight, *passedJobArrays, nodes);
112123}
113124
114- void InteriorSunShadows ::ClearArrays ()
125+ void InteriorSun ::ClearArrays ()
115126{
116127 currentCellRoomsAndPortals.clear ();
117128
@@ -127,7 +138,7 @@ namespace RE
127138 {};
128139}
129140
130- void InteriorSunShadows ::PopulateReplacementJobArrays (RE::TESObjectCELL* cell, const RE::NiPointer<RE::BSPortalGraph>& portalGraph, const RE::BSShadowDirectionalLight* dirLight, RE::BSTArray<RE::BSTArray<RE::NiPointer<RE::NiAVObject>>>& jobArrays)
141+ void InteriorSun ::PopulateReplacementJobArrays (RE::TESObjectCELL* cell, const RE::NiPointer<RE::BSPortalGraph>& portalGraph, const RE::BSShadowDirectionalLight* dirLight, RE::BSTArray<RE::BSTArray<RE::NiPointer<RE::NiAVObject>>>& jobArrays)
131142{
132143 if (cell != currentCell) {
133144 InitialiseOnNewCell (portalGraph);
@@ -170,7 +181,7 @@ void InteriorSunShadows::PopulateReplacementJobArrays(RE::TESObjectCELL* cell, c
170181 arraysCleared = false ;
171182}
172183
173- void InteriorSunShadows ::InitialiseOnNewCell (const RE::NiPointer<RE::BSPortalGraph>& portalGraph)
184+ void InteriorSun ::InitialiseOnNewCell (const RE::NiPointer<RE::BSPortalGraph>& portalGraph)
174185{
175186 currentCellRoomsAndPortals.clear ();
176187
@@ -183,11 +194,18 @@ void InteriorSunShadows::InitialiseOnNewCell(const RE::NiPointer<RE::BSPortalGra
183194 }
184195}
185196
186- bool InteriorSunShadows ::IsInSunDirectionAndWithinShadowDistance (const RE::NiPointer<RE::NiAVObject>& object, const RE::NiPoint3& lightDir, const RE::NiPoint3& playerPos) const
197+ bool InteriorSun ::IsInSunDirectionAndWithinShadowDistance (const RE::NiPointer<RE::NiAVObject>& object, const RE::NiPoint3& lightDir, const RE::NiPoint3& playerPos) const
187198{
188199 const float radius = object->worldBound .radius ;
189200 const auto diff = object->worldBound .center - playerPos;
190201 const float distance = diff.Length ();
191202 const float projection = lightDir.Dot (diff);
192203 return projection >= -radius && (distance - radius) <= *gShadowDistance ;
204+ }
205+
206+ void InteriorSun::SetShadowDistance (bool inInterior)
207+ {
208+ using func_t = decltype (SetShadowDistance);
209+ static REL::Relocation<func_t > func{ REL::RelocationID (98978 , 105631 ).address () };
210+ func (inInterior);
193211}
0 commit comments