Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/Features/InteriorSunShadows.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "InteriorSunShadows.h"
#include "InteriorSunShadows.h"
#include "State.h"

#include <numbers>
Expand Down Expand Up @@ -44,11 +44,27 @@ void InteriorSunShadows::EarlyPrepass()
isInteriorWithSun = IsInteriorWithSun(globals::game::tes->interiorCell);
}

/**
* @brief Determines if a cell is an interior that supports sun lighting and shadows.
*
* Returns true if the given cell is non-null and has the flags for interior cell, show sky, use sky lighting, and sunlight shadows all set.
*
* @param cell Pointer to the cell to check.
* @return true if the cell is an interior with sun lighting and shadows enabled; false otherwise.
*/
inline bool InteriorSunShadows::IsInteriorWithSun(const RE::TESObjectCELL* cell)
{
return cell && cell->cellFlags.all(RE::TESObjectCELL::Flag::kIsInteriorCell, RE::TESObjectCELL::Flag::kShowSky, RE::TESObjectCELL::Flag::kUseSkyLighting);
return cell && cell->cellFlags.all(RE::TESObjectCELL::Flag::kIsInteriorCell, RE::TESObjectCELL::Flag::kShowSky, RE::TESObjectCELL::Flag::kUseSkyLighting, static_cast<RE::TESObjectCELL::Flag>(CellFlagExt::kSunlightShadows));
}

/**
* @brief Returns a dummy TESWorldSpace object based on whether the TES object's interior cell supports sun shadows.
*
* If the TES object's interior cell exists and qualifies as an interior with sun (per IsInteriorWithSun), returns a special dummy TESWorldSpace to enable sun shadows. Otherwise, returns a dummy TESWorldSpace that disables sun shadows. Falls back to the original GetWorldSpace function if no interior cell is present.
*
* @param tes The TES object whose world space is being queried.
* @return TESWorldSpace* A pointer to the appropriate dummy TESWorldSpace or the result of the original function.
*/
RE::TESWorldSpace* InteriorSunShadows::GetWorldSpace::thunk(RE::TES* tes)
{
if (const auto cell = tes->interiorCell)
Expand Down
17 changes: 14 additions & 3 deletions src/Features/InteriorSunShadows.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
#pragma once
#pragma once
#include "ShaderCache.h"

/**
* @brief Determines if the specified cell is an interior that receives sunlight.
*
* @param cell Pointer to the cell to check.
* @return true if the cell is an interior with sunlight; otherwise, false.
*/
struct InteriorSunShadows : Feature
{
static InteriorSunShadows* GetSingleton()
Expand Down Expand Up @@ -51,7 +57,14 @@ struct InteriorSunShadows : Feature
}
}

static bool IsInteriorWithSun(const RE::TESObjectCELL* cell);

private:
enum class CellFlagExt : uint16_t
{
kSunlightShadows = 1 << 15,
};

float* gShadowDistance = nullptr;
uint32_t* rasterStateCullMode = nullptr;

Expand All @@ -69,8 +82,6 @@ struct InteriorSunShadows : Feature

void InitialiseOnNewCell(const RE::NiPointer<RE::BSPortalGraph>& portalGraph);

static bool IsInteriorWithSun(const RE::TESObjectCELL* cell);

bool IsInSunDirectionAndWithinShadowDistance(const RE::NiPointer<RE::NiAVObject>& object, const RE::NiPoint3& lightDir, const RE::NiPoint3& playerPos) const;

void PopulateReplacementJobArrays(RE::TESObjectCELL* cell, const RE::NiPointer<RE::BSPortalGraph>& portalGraph, const RE::BSShadowDirectionalLight* dirLight, RE::BSTArray<RE::BSTArray<RE::NiPointer<RE::NiAVObject>>>& jobArrays);
Expand Down
8 changes: 7 additions & 1 deletion src/Features/VolumetricLighting.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "VolumetricLighting.h"

#include "InteriorSunShadows.h"
#include "ShaderCache.h"
#include "State.h"

Expand Down Expand Up @@ -179,6 +180,11 @@ void VolumetricLighting::PostPostLoad()
defaultSizeHigh = *gVolumetricLightingSizeHigh;
}

/**
* @brief Updates volumetric lighting state based on the player's current location.
*
* Detects whether the player has entered or exited an interior cell and whether the interior supports sun shadows. Applies appropriate volumetric lighting settings if the state has changed.
*/
void VolumetricLighting::EarlyPrepass()
{
const auto interiorCell = globals::game::tes->interiorCell;
Expand All @@ -189,7 +195,7 @@ void VolumetricLighting::EarlyPrepass()

initialised = true;
inInterior = currentlyInInterior;
inInteriorWithSunShadows = interiorCell && interiorCell->cellFlags.all(RE::TESObjectCELL::Flag::kIsInteriorCell, RE::TESObjectCELL::Flag::kShowSky, RE::TESObjectCELL::Flag::kUseSkyLighting);
inInteriorWithSunShadows = InteriorSunShadows::IsInteriorWithSun(interiorCell);
SetupVL();
}

Expand Down
Loading