mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-09 05:47:42 +00:00
Implement CActorLights::BuildAreaLightList
This commit is contained in:
@@ -1,21 +1,28 @@
|
||||
#include "CActorLights.hpp"
|
||||
#include "Graphics/CModel.hpp"
|
||||
#include "World/CGameArea.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include "Collision/CGameCollision.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
||||
s32 CActorLights::sFrameSchedulerCount = 0;
|
||||
CActorLights::CActorLights(u32 unk, const zeus::CVector3f& vec, int a, int b, bool c, int d, int e, float f1)
|
||||
: x2a8_(unk), x2ac_(vec), x2b8_b(b), x2bc_a(a), x2cc_(f1 * f1)
|
||||
CActorLights::CActorLights(u32 areaUpdateFramePeriod, const zeus::CVector3f& actorPosBias,
|
||||
int maxDynamicLights, int maxAreaLights, bool ambientChannelOverflow,
|
||||
bool layer2, bool disableWorldLights, float positionUpdateThreshold)
|
||||
: x2a8_areaUpdateFramePeriod(areaUpdateFramePeriod), x2ac_actorPosBias(actorPosBias),
|
||||
x2b8_maxAreaLights(maxAreaLights), x2bc_maxDynamicLights(maxDynamicLights),
|
||||
x2cc_actorPositionDeltaUpdateThreshold(positionUpdateThreshold * positionUpdateThreshold)
|
||||
{
|
||||
x298_24_ = true;
|
||||
x298_25_ = true;
|
||||
x298_24_dirty = true;
|
||||
x298_25_castShadows = true;
|
||||
|
||||
x298_28_inArea = (!e && b > 0) ? true : false;
|
||||
x298_29_ = c;
|
||||
x298_30_ = d;
|
||||
x298_31_ = e;
|
||||
x299_24_ = true;
|
||||
x298_28_inArea = (!disableWorldLights && maxAreaLights > 0) ? true : false;
|
||||
x298_29_ambientChannelOverflow = ambientChannelOverflow;
|
||||
x298_30_layer2 = layer2;
|
||||
x298_31_disableWorldLights = disableWorldLights;
|
||||
x299_24_inBrightLight = true;
|
||||
|
||||
sFrameSchedulerCount++;
|
||||
sFrameSchedulerCount &= 7;
|
||||
@@ -24,9 +31,9 @@ CActorLights::CActorLights(u32 unk, const zeus::CVector3f& vec, int a, int b, bo
|
||||
void CActorLights::BuildConstantAmbientLighting()
|
||||
{
|
||||
x299_26_ = true;
|
||||
x298_24_ = true;
|
||||
x29c_ = -1;
|
||||
x2a0_ = -1;
|
||||
x298_24_dirty = true;
|
||||
x29c_shadowLightValIdx = -1;
|
||||
x2a0_shadowLightIdx = -1;
|
||||
}
|
||||
|
||||
void CActorLights::BuildConstantAmbientLighting(const zeus::CColor& color)
|
||||
@@ -34,10 +41,10 @@ void CActorLights::BuildConstantAmbientLighting(const zeus::CColor& color)
|
||||
x299_26_ = false;
|
||||
x288_ambientColor = color;
|
||||
x294_aid = kInvalidAreaId;
|
||||
x298_24_ = true;
|
||||
x298_26_ = true;
|
||||
x29c_ = -1;
|
||||
x2a0_ = -1;
|
||||
x298_24_dirty = true;
|
||||
x298_26_hasAreaLights = true;
|
||||
x29c_shadowLightValIdx = -1;
|
||||
x2a0_shadowLightIdx = -1;
|
||||
}
|
||||
|
||||
void CActorLights::BuildFakeLightList(const std::vector<CLight>& lights, const zeus::CColor& color)
|
||||
@@ -50,11 +57,299 @@ void CActorLights::BuildFaceLightList(CStateManager& mgr, const CGameArea& area,
|
||||
{
|
||||
}
|
||||
|
||||
void CActorLights::BuildDynamicLightList(CStateManager& mgr, const zeus::CAABox& aabb)
|
||||
struct SLightValue
|
||||
{
|
||||
u32 x0_areaLightIdx;
|
||||
zeus::CColor x4_color;
|
||||
float x10_colorMag;
|
||||
float x14_accumulatedMag = 0.f;
|
||||
EPVSVisSetState x18_visiblity;
|
||||
};
|
||||
|
||||
void CActorLights::MergeOverflowLight(CLight& out, zeus::CColor& color, const CLight& in, float colorMag)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CActorLights::MoveAmbienceToLights(const zeus::CVector3f& vec)
|
||||
void CActorLights::AddOverflowToLights(const CLight& light, const zeus::CColor& color, float mag)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CActorLights::MoveAmbienceToLights(const zeus::CColor& color)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CActorLights::MultiplyLightingLevels(float level)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CActorLights::BuildAreaLightList(CStateManager& mgr, const CGameArea& area, const zeus::CAABox& aabb)
|
||||
{
|
||||
const std::vector<CWorldLight>& lightList = x298_30_layer2 ? area.GetPostConstructed()->x80_lightsB :
|
||||
area.GetPostConstructed()->x60_lightsA;
|
||||
const std::vector<CLight>& gfxLightList = x298_30_layer2 ? area.GetPostConstructed()->x90_gfxLightsB :
|
||||
area.GetPostConstructed()->x70_gfxLightsA;
|
||||
float worldLightingLevel = area.GetPostConstructed()->x1128_worldLightingLevel;
|
||||
x298_26_hasAreaLights = lightList.size() != 0;
|
||||
if (!x298_26_hasAreaLights || !x298_28_inArea)
|
||||
{
|
||||
/* World lights disabled */
|
||||
if (x298_31_disableWorldLights)
|
||||
x2d4_worldLightingLevel = worldLightingLevel;
|
||||
x29c_shadowLightValIdx = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
zeus::CVector3f vec;
|
||||
if (!x298_24_dirty && x294_aid == area.GetAreaId())
|
||||
{
|
||||
/* Early return if not ready for update */
|
||||
if (mgr.GetInputFrameIdx() - x2a4_lastUpdateFrame < x2a8_areaUpdateFramePeriod)
|
||||
return false;
|
||||
vec = aabb.center() + x2ac_actorPosBias;
|
||||
if (x2d4_worldLightingLevel == worldLightingLevel)
|
||||
if ((x2c0_lastActorPos - vec).magSquared() < x2cc_actorPositionDeltaUpdateThreshold)
|
||||
return false;
|
||||
x2c0_lastActorPos = vec;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x294_aid != area.GetAreaId())
|
||||
x2d8_brightLightIdx = -1;
|
||||
x2a4_lastUpdateFrame = sFrameSchedulerCount + mgr.GetInputFrameIdx();
|
||||
vec = aabb.center() + x2ac_actorPosBias;
|
||||
x2c0_lastActorPos = vec;
|
||||
}
|
||||
|
||||
/* Reset lighting state */
|
||||
x2d4_worldLightingLevel = worldLightingLevel;
|
||||
x298_24_dirty = false;
|
||||
x294_aid = area.GetAreaId();
|
||||
x29c_shadowLightValIdx = -1;
|
||||
x288_ambientColor = zeus::CColor::skClear;
|
||||
|
||||
/* Find candidate lights via PVS */
|
||||
bool use2ndLayer;
|
||||
if (x298_30_layer2)
|
||||
{
|
||||
if (const CPVSAreaSet* pvs = area.GetAreaVisSet())
|
||||
use2ndLayer = pvs->Has2ndLayerLights();
|
||||
else
|
||||
use2ndLayer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
use2ndLayer = false;
|
||||
}
|
||||
|
||||
CPVSVisSet sets[3];
|
||||
sets[0].Reset(EPVSVisSetState::OutOfBounds);
|
||||
sets[1].Reset(EPVSVisSetState::OutOfBounds);
|
||||
sets[2].Reset(EPVSVisSetState::OutOfBounds);
|
||||
|
||||
if (const CPVSAreaSet* pvs = area.GetAreaVisSet())
|
||||
{
|
||||
zeus::CVector3f localVec = area.GetInverseTransform() * vec;
|
||||
sets[0].SetTestPoint(pvs->GetVisOctree(), localVec);
|
||||
localVec = area.GetInverseTransform() * aabb.max;
|
||||
sets[1].SetTestPoint(pvs->GetVisOctree(), localVec);
|
||||
localVec = area.GetInverseTransform() * aabb.min;
|
||||
sets[2].SetTestPoint(pvs->GetVisOctree(), localVec);
|
||||
}
|
||||
|
||||
std::vector<SLightValue> valList;
|
||||
valList.reserve(lightList.size());
|
||||
|
||||
auto lightIt = lightList.begin();
|
||||
int lightIdx = 0;
|
||||
for (const CLight& light : gfxLightList)
|
||||
{
|
||||
if (light.GetType() == ELightType::LocalAmbient)
|
||||
{
|
||||
/* Take ambient here */
|
||||
x288_ambientColor = light.GetNormalIndependentLightingAtPoint(vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
EPVSVisSetState visible = EPVSVisSetState::OutOfBounds;
|
||||
if (area.GetAreaVisSet())
|
||||
{
|
||||
if (lightIt->DoesCastShadows())
|
||||
{
|
||||
u32 pvsIdx;
|
||||
if (use2ndLayer)
|
||||
pvsIdx = area.Get2ndPVSLightFeature(lightIdx);
|
||||
else
|
||||
pvsIdx = area.Get1stPVSLightFeature(lightIdx);
|
||||
visible = sets[0].GetVisible(pvsIdx);
|
||||
if (visible != EPVSVisSetState::OutOfBounds)
|
||||
visible = std::max(visible, sets[1].GetVisible(pvsIdx));
|
||||
if (visible != EPVSVisSetState::OutOfBounds)
|
||||
visible = std::max(visible, sets[2].GetVisible(pvsIdx));
|
||||
}
|
||||
}
|
||||
if (visible != EPVSVisSetState::EndOfTree)
|
||||
{
|
||||
zeus::CSphere sphere(light.GetPosition(), light.GetRadius() * 2.f);
|
||||
if (aabb.intersects(sphere))
|
||||
{
|
||||
/* Light passes as candidate */
|
||||
valList.emplace_back();
|
||||
SLightValue& value = valList.back();
|
||||
value.x0_areaLightIdx = lightIdx;
|
||||
value.x4_color = light.GetNormalIndependentLightingAtPoint(vec);
|
||||
value.x4_color.a = 0.f;
|
||||
value.x10_colorMag = value.x4_color.magnitude();
|
||||
value.x18_visiblity = visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
++lightIt;
|
||||
++lightIdx;
|
||||
}
|
||||
|
||||
/* Sort lights most intense to least intense */
|
||||
std::sort(valList.begin(), valList.end(),
|
||||
[](const SLightValue& a, const SLightValue& b)
|
||||
{
|
||||
return a.x10_colorMag >= b.x10_colorMag;
|
||||
});
|
||||
|
||||
if (x298_27_findShadowLight)
|
||||
{
|
||||
/* Accumulate magnitudes up to most intense for shadow dynamic range check */
|
||||
x288_ambientColor.a = 0.f;
|
||||
float mag = x288_ambientColor.magnitude();
|
||||
for (auto it = valList.rbegin() ; it != valList.rend() ; ++it)
|
||||
{
|
||||
mag += it->x10_colorMag;
|
||||
it->x14_accumulatedMag = mag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ambient color for overflow area lights */
|
||||
zeus::CColor overflowAmbColor;
|
||||
|
||||
/* Averaged light for overflow area lights */
|
||||
CLight overflowLight = CLight::BuildCustom(zeus::CVector3f::skZero, zeus::CVector3f::skZero, zeus::CColor::skBlack,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
zeus::CColor overflowLightColor;
|
||||
float overflowMag = 0.f;
|
||||
|
||||
/* Max significant lights */
|
||||
int maxAreaLights = !x298_29_ambientChannelOverflow ? x2b8_maxAreaLights - 1 : x2b8_maxAreaLights;
|
||||
x0_areaLights.clear();
|
||||
|
||||
/* Filter for performing final light visibility test */
|
||||
CMaterialFilter filter =
|
||||
CMaterialFilter::MakeIncludeExclude(CMaterialList(EMaterialTypes::Solid),
|
||||
CMaterialList(EMaterialTypes::Projectile, EMaterialTypes::ProjectilePassthrough,
|
||||
EMaterialTypes::SeeThrough));
|
||||
u32 mostSigLightIdx = 0;
|
||||
|
||||
/* Narrowphase test candidates starting with most intense */
|
||||
for (int i=0 ; i<valList.size() ; ++i)
|
||||
{
|
||||
const SLightValue& value = valList[i];
|
||||
const CLight& light = gfxLightList[value.x0_areaLightIdx];
|
||||
if (x0_areaLights.size() < maxAreaLights)
|
||||
{
|
||||
/* Significant light */
|
||||
bool actorToLightContact = true;
|
||||
bool castShadows = lightList[value.x0_areaLightIdx].DoesCastShadows() && x298_25_castShadows;
|
||||
bool outOfBounds = area.GetAreaVisSet() && value.x18_visiblity == EPVSVisSetState::OutOfBounds;
|
||||
if (castShadows)
|
||||
{
|
||||
/* Process shadow cast */
|
||||
zeus::CVector3f delta = light.GetPosition() - vec;
|
||||
float deltaMag = delta.magnitude();
|
||||
bool useShadow = false;
|
||||
if (x298_27_findShadowLight && x29c_shadowLightValIdx == -1 && light.GetType() != ELightType::LocalAmbient &&
|
||||
deltaMag > 2.f && !aabb.pointInside(light.GetPosition()))
|
||||
{
|
||||
/* Perform shadow dynamic range check */
|
||||
if (!x0_areaLights.size() ||
|
||||
(x0_areaLights.size() == 1 && value.x10_colorMag / valList[mostSigLightIdx].x10_colorMag > 0.5f))
|
||||
{
|
||||
useShadow = value.x10_colorMag / value.x14_accumulatedMag >
|
||||
x2d0_shadowDynamicRangeThreshold / (1.f + x2d0_shadowDynamicRangeThreshold);
|
||||
}
|
||||
}
|
||||
if (useShadow)
|
||||
{
|
||||
/* Note shadow light */
|
||||
x29c_shadowLightValIdx = x0_areaLights.size();
|
||||
x2a0_shadowLightIdx = value.x0_areaLightIdx;
|
||||
}
|
||||
else if (!outOfBounds)
|
||||
{
|
||||
/* Note brightest light contact */
|
||||
delta = delta * 1.f / deltaMag;
|
||||
actorToLightContact = CGameCollision::TestLightRayIntersection(area, vec, delta, deltaMag, filter);
|
||||
if (i == 0)
|
||||
{
|
||||
x299_24_inBrightLight = actorToLightContact;
|
||||
if (x2d8_brightLightIdx != value.x0_areaLightIdx)
|
||||
{
|
||||
x2dc_overrideDist = actorToLightContact ? 0 : 15;
|
||||
x2d8_brightLightIdx = value.x0_areaLightIdx;
|
||||
}
|
||||
x299_25_overrideFirstDist = false;
|
||||
actorToLightContact = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (actorToLightContact)
|
||||
{
|
||||
/* Add to final list */
|
||||
if (x0_areaLights.size() == 0)
|
||||
mostSigLightIdx = i;
|
||||
x0_areaLights.push_back(light);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Overflow light */
|
||||
if (!x298_29_ambientChannelOverflow && value.x10_colorMag > 0.001f)
|
||||
{
|
||||
/* Average parameters into final light */
|
||||
MergeOverflowLight(overflowLight, overflowLightColor, light, value.x10_colorMag);
|
||||
overflowMag += value.x10_colorMag;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Average color into ambient channel */
|
||||
overflowAmbColor += value.x4_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finalize overflow lights */
|
||||
if (!x298_29_ambientChannelOverflow)
|
||||
AddOverflowToLights(overflowLight, overflowLightColor, overflowMag);
|
||||
else
|
||||
MoveAmbienceToLights(overflowAmbColor);
|
||||
|
||||
/* Clamp ambient color */
|
||||
if (x288_ambientColor.r > 1.f)
|
||||
x288_ambientColor.r = 1.f;
|
||||
if (x288_ambientColor.g > 1.f)
|
||||
x288_ambientColor.g = 1.f;
|
||||
if (x288_ambientColor.b > 1.f)
|
||||
x288_ambientColor.b = 1.f;
|
||||
x288_ambientColor.a = 1.f;
|
||||
|
||||
/* Multiply down lighting with world fader level */
|
||||
if (worldLightingLevel < 1.f)
|
||||
MultiplyLightingLevels(worldLightingLevel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CActorLights::BuildDynamicLightList(CStateManager& mgr, const zeus::CAABox& aabb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -63,7 +358,7 @@ void CActorLights::ActivateLights(CBooModel& model) const
|
||||
std::vector<CLight> lights;
|
||||
if (x298_28_inArea)
|
||||
{
|
||||
if (!x298_26_ || !x299_26_)
|
||||
if (!x298_26_hasAreaLights || !x299_26_)
|
||||
{
|
||||
model.ActivateLights(lights);
|
||||
//return;
|
||||
|
||||
Reference in New Issue
Block a user