From 84578e9909ec6af1920c0bdd1c9999bc94de08de Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 9 Apr 2017 20:57:00 -1000 Subject: [PATCH] Implement CActorLights::BuildAreaLightList --- DataSpec/DNAMP1/MREA.cpp | 33 +- DataSpec/DNAMP1/ScriptObjects/Parameters.hpp | 14 +- DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp | 8 +- Runtime/CStateManager.hpp | 1 + Runtime/Character/CActorLights.cpp | 333 +++++++++++++++++-- Runtime/Character/CActorLights.hpp | 52 +-- Runtime/Collision/CGameCollision.cpp | 10 + Runtime/Collision/CGameCollision.hpp | 3 + Runtime/Graphics/CLight.cpp | 9 + Runtime/Graphics/CLight.hpp | 1 + Runtime/Graphics/CPVSAreaSet.cpp | 2 +- Runtime/Graphics/CPVSAreaSet.hpp | 7 +- Runtime/MP1/CSamusHud.cpp | 5 +- Runtime/World/CGameArea.hpp | 5 + Runtime/World/CLightParameters.hpp | 81 ++--- Runtime/World/CWorldLight.hpp | 2 +- Runtime/World/ScriptLoader.cpp | 29 +- visigen/VISIBuilder.cpp | 3 +- visigen/VISIBuilder.hpp | 1 + visigen/VISIRenderer.cpp | 5 +- 20 files changed, 477 insertions(+), 127 deletions(-) diff --git a/DataSpec/DNAMP1/MREA.cpp b/DataSpec/DNAMP1/MREA.cpp index 3a02505c7..6e5c92d90 100644 --- a/DataSpec/DNAMP1/MREA.cpp +++ b/DataSpec/DNAMP1/MREA.cpp @@ -167,12 +167,15 @@ bool MREA::Extract(const SpecBase& dataSpec, rs.seek(secStart + head.secSizes[curSec++], athena::Begin); /* Dump VISI entities */ + auto visiPos = rs.position(); if (head.secSizes[curSec] && rs.readUint32Big() == 'VISI') { athena::io::YAMLDocWriter visiWriter("VISI"); + uint32_t unkCount = 0; if (auto __vec = visiWriter.enterSubVector("entities")) { - rs.seek(18, athena::Current); + rs.seek(14, athena::Current); + unkCount = rs.readUint32Big(); uint32_t entityCount = rs.readUint32Big(); rs.seek(8, athena::Current); for (int i=0 ; i lightsVisi; + std::vector lightsVisi[2]; { - int actualCount = 0; + int actualCounts[2] = {}; for (const Light& l : lights) if (l.layer == 0 || l.layer == 1) - ++actualCount; - lightsVisi.reserve(actualCount); + ++actualCounts[l.layer]; + lightsVisi[0].reserve(actualCounts[0]); + lightsVisi[1].reserve(actualCounts[1]); - secs.emplace_back(12 + 65 * actualCount, 0); + secs.emplace_back(12 + 65 * (actualCounts[0] + actualCounts[1]), 0); athena::io::MemoryWriter w(secs.back().data(), secs.back().size()); w.writeUint32Big(0xBABEDEAD); @@ -426,7 +438,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath, BabeDeadLight light = {}; WriteBabeDeadLightFromBlender(light, l); light.write(w); - lightsVisi.push_back(light.position); + lightsVisi[l.layer].push_back(light.position); } } } @@ -495,8 +507,11 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath, w.writeVec3fBig(ent.second.max); } - w.writeUint32Big(lightsVisi.size()); - for (const auto& light : lightsVisi) + w.writeUint32Big(lightsVisi[0].size() + lightsVisi[1].size()); + w.writeUint32Big(lightsVisi[1].size()); + for (const auto& light : lightsVisi[1]) + w.writeVec3fBig(light); + for (const auto& light : lightsVisi[0]) w.writeVec3fBig(light); w.close(); diff --git a/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp b/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp index 05da47569..88e45ae34 100644 --- a/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp +++ b/DataSpec/DNAMP1/ScriptObjects/Parameters.hpp @@ -237,15 +237,15 @@ struct LightParameters : BigYAML Value shadowTesselation; Value unknown3; Value unknown4; - Value unknown5; // CColor - Value unknown6; + Value noLightsAmbient; // CColor + Value makeLights; Value worldLightingOptions; Value lightRecalculationOptions; - Value unknown7; - Value unknown8; - Value unknown9; - Value unknown10; - Value unknown11; + Value actorPosBias; + Value maxDynamicLights; + Value maxAreaLights; + Value ambientChannelOverflow; + Value layerIndex; }; struct PatternedInfo : BigYAML diff --git a/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp index 18bc609aa..94d334f65 100644 --- a/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp +++ b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp @@ -1071,8 +1071,8 @@ void CTweakPlayer::read(athena::io::YAMLDocReader& __dna_docin) x130_ = __dna_docin.readFloat("x130_"); /* x134_ */ x134_ = __dna_docin.readFloat("x134_"); - /* x138_ */ - x138_hudLagAmount = __dna_docin.readFloat("x138_"); + /* x138_hudLagAmount */ + x138_hudLagAmount = __dna_docin.readFloat("x138_hudLagAmount"); /* x13c_ */ x13c_ = __dna_docin.readFloat("x13c_"); /* x140_ */ @@ -1580,8 +1580,8 @@ void CTweakPlayer::CTweakPlayer::write(athena::io::YAMLDocWriter& __dna_docout) __dna_docout.writeFloat("x130_", x130_); /* x134_ */ __dna_docout.writeFloat("x134_", x134_); - /* x138_ */ - __dna_docout.writeFloat("x138_", x138_hudLagAmount); + /* x138_hudLagAmount */ + __dna_docout.writeFloat("x138_hudLagAmount", x138_hudLagAmount); /* x13c_ */ __dna_docout.writeFloat("x13c_", x13c_); /* x140_ */ diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index cfad2ba18..ba25a8cae 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -261,6 +261,7 @@ public: const std::weak_ptr&, const std::weak_ptr&); + u32 GetInputFrameIdx() const { return x8d4_inputFrameIdx; } bool RenderLast(TUniqueId); void AddDrawableActorPlane(const CActor& actor, const zeus::CPlane&, const zeus::CAABox& aabb) const; void AddDrawableActor(const CActor& actor, const zeus::CVector3f& vec, const zeus::CAABox& aabb) const; diff --git a/Runtime/Character/CActorLights.cpp b/Runtime/Character/CActorLights.cpp index be2ece434..8d9d33b81 100644 --- a/Runtime/Character/CActorLights.cpp +++ b/Runtime/Character/CActorLights.cpp @@ -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& 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& lightList = x298_30_layer2 ? area.GetPostConstructed()->x80_lightsB : + area.GetPostConstructed()->x60_lightsA; + const std::vector& 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 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 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 lights; if (x298_28_inArea) { - if (!x298_26_ || !x299_26_) + if (!x298_26_hasAreaLights || !x299_26_) { model.ActivateLights(lights); //return; diff --git a/Runtime/Character/CActorLights.hpp b/Runtime/Character/CActorLights.hpp index 93c781b0c..010eee544 100644 --- a/Runtime/Character/CActorLights.hpp +++ b/Runtime/Character/CActorLights.hpp @@ -25,45 +25,53 @@ class CActorLights { struct { - bool x298_24_ : 1; - bool x298_25_ : 1; - bool x298_26_ : 1; - bool x298_27_ : 1; + bool x298_24_dirty : 1; + bool x298_25_castShadows : 1; + bool x298_26_hasAreaLights : 1; + bool x298_27_findShadowLight : 1; bool x298_28_inArea : 1; - bool x298_29_ : 1; - bool x298_30_ : 1; - bool x298_31_ : 1; - bool x299_24_ : 1; + bool x298_29_ambientChannelOverflow : 1; + bool x298_30_layer2 : 1; + bool x298_31_disableWorldLights : 1; + bool x299_24_inBrightLight : 1; bool x299_25_overrideFirstDist : 1; bool x299_26_ : 1; }; u16 _dummy = 0; }; bool x29a_ = false; - u32 x29c_ = -1; - u32 x2a0_ = -1; - u32 x2a4_ = 0; - u32 x2a8_; - zeus::CVector3f x2ac_; - int x2b8_b; - int x2bc_a; - zeus::CVector3f x2c0_; - float x2cc_; - float x2d0_ = 0.f; - float x2d4_ = 1.f; - u32 x2d8_ = -1; + u32 x29c_shadowLightValIdx = -1; + u32 x2a0_shadowLightIdx = -1; + u32 x2a4_lastUpdateFrame = 0; + u32 x2a8_areaUpdateFramePeriod; + zeus::CVector3f x2ac_actorPosBias; + int x2b8_maxAreaLights; + int x2bc_maxDynamicLights; + zeus::CVector3f x2c0_lastActorPos; + float x2cc_actorPositionDeltaUpdateThreshold; + float x2d0_shadowDynamicRangeThreshold = 0.f; + float x2d4_worldLightingLevel = 1.f; + u32 x2d8_brightLightIdx = -1; u32 x2dc_overrideDist = 0; + static void MergeOverflowLight(CLight& out, zeus::CColor& color, const CLight& in, float colorMag); + void AddOverflowToLights(const CLight& light, const zeus::CColor& color, float mag); + void MoveAmbienceToLights(const zeus::CColor& color); + void MultiplyLightingLevels(float level); + public: - CActorLights(u32, const zeus::CVector3f& vec, int, int, bool, int, int, float); + CActorLights(u32 areaUpdateFramePeriod, const zeus::CVector3f& actorPosBias, + int maxDynamicLights, int maxAreaLights, bool ambientChannelOverflow, + bool layer2, bool disableWorldLights, float positionUpdateThreshold); void BuildConstantAmbientLighting(); void BuildConstantAmbientLighting(const zeus::CColor& color); void BuildFakeLightList(const std::vector& lights, const zeus::CColor& color); void BuildFaceLightList(CStateManager& mgr, const CGameArea& area, const zeus::CAABox& aabb); + bool BuildAreaLightList(CStateManager& mgr, const CGameArea& area, const zeus::CAABox& aabb); void BuildDynamicLightList(CStateManager& mgr, const zeus::CAABox& aabb); - void MoveAmbienceToLights(const zeus::CVector3f& vec); void ActivateLights(CBooModel& model) const; + void SetCastShadows(bool v) { x298_25_castShadows = v; } void SetAmbientColor(const zeus::CColor& color) { x288_ambientColor = color; } const CLight& GetLight(u32 idx) const; diff --git a/Runtime/Collision/CGameCollision.cpp b/Runtime/Collision/CGameCollision.cpp index 44281ce86..a04cf3284 100644 --- a/Runtime/Collision/CGameCollision.cpp +++ b/Runtime/Collision/CGameCollision.cpp @@ -158,4 +158,14 @@ CGameCollision::RayWorldIntersection(const CStateManager& mgr, TUniqueId& idOut, else return staticRes; } + +bool CGameCollision::TestLightRayIntersection(const CGameArea& area, const zeus::CVector3f& pos, + const zeus::CVector3f& dir, float mag, const CMaterialFilter& filter) +{ + if (mag <= 0.f) + mag = 100000.f; + CAreaOctTree::Node node = area.GetPostConstructed()->x0_collision->GetRootNode(); + zeus::CLine line(pos, dir); + return node.LineTest(line, filter, mag); +} } diff --git a/Runtime/Collision/CGameCollision.hpp b/Runtime/Collision/CGameCollision.hpp index c470bcad1..c245fd34f 100644 --- a/Runtime/Collision/CGameCollision.hpp +++ b/Runtime/Collision/CGameCollision.hpp @@ -20,6 +20,7 @@ class CMaterialList; class CStateManager; class CPhysicsActor; class CMaterialFilter; +class CGameArea; class CGameCollision { @@ -44,6 +45,8 @@ public: static CRayCastResult RayWorldIntersection(const CStateManager& mgr, TUniqueId& idOut, const zeus::CVector3f& pos, const zeus::CVector3f& dir, float mag, const CMaterialFilter& filter, const rstl::reserved_vector& nearList); + static bool TestLightRayIntersection(const CGameArea& area, const zeus::CVector3f& pos, + const zeus::CVector3f& dir, float mag, const CMaterialFilter& filter); }; } diff --git a/Runtime/Graphics/CLight.cpp b/Runtime/Graphics/CLight.cpp index 1a57b7404..c52fbb4ce 100644 --- a/Runtime/Graphics/CLight.cpp +++ b/Runtime/Graphics/CLight.cpp @@ -86,6 +86,15 @@ CLight::CLight(ELightType type, } } +zeus::CColor CLight::GetNormalIndependentLightingAtPoint(const zeus::CVector3f& point) const +{ + if (x1c_type == ELightType::LocalAmbient) + return x18_color; + + float dist = std::max((x0_pos - point).magnitude(), FLT_EPSILON); + return x18_color * (1.f / (x2c_distQ * dist * dist + x28_distL * dist + x24_distC)); +} + CLight CLight::BuildDirectional(const zeus::CVector3f& dir, const zeus::CColor& color) { return CLight(ELightType::Directional, kDefaultPosition, dir, color, 180.f); diff --git a/Runtime/Graphics/CLight.hpp b/Runtime/Graphics/CLight.hpp index 62e8f4e69..00f01d394 100644 --- a/Runtime/Graphics/CLight.hpp +++ b/Runtime/Graphics/CLight.hpp @@ -116,6 +116,7 @@ public: float GetIntensity() const; const zeus::CColor& GetColor() const { return x18_color; } + zeus::CColor GetNormalIndependentLightingAtPoint(const zeus::CVector3f& point) const; static CLight BuildDirectional(const zeus::CVector3f& dir, const zeus::CColor& color); static CLight BuildSpot(const zeus::CVector3f& pos, const zeus::CVector3f& dir, diff --git a/Runtime/Graphics/CPVSAreaSet.cpp b/Runtime/Graphics/CPVSAreaSet.cpp index e2138020c..834692e25 100644 --- a/Runtime/Graphics/CPVSAreaSet.cpp +++ b/Runtime/Graphics/CPVSAreaSet.cpp @@ -8,7 +8,7 @@ CPVSAreaSet::CPVSAreaSet(const u8* data, u32 len) CMemoryInStream r(data, len); x0_numFeatures = r.readUint32Big(); x4_numLights = r.readUint32Big(); - x8_c = r.readUint32Big(); + x8_num2ndLights = r.readUint32Big(); xc_numActors = r.readUint32Big(); x10_leafSize = r.readUint32Big(); x14_lightIndexCount = r.readUint32Big(); diff --git a/Runtime/Graphics/CPVSAreaSet.hpp b/Runtime/Graphics/CPVSAreaSet.hpp index f837c3ab9..fda5f0969 100644 --- a/Runtime/Graphics/CPVSAreaSet.hpp +++ b/Runtime/Graphics/CPVSAreaSet.hpp @@ -11,7 +11,7 @@ class CPVSAreaSet { u32 x0_numFeatures; u32 x4_numLights; - u32 x8_c; + u32 x8_num2ndLights; u32 xc_numActors; u32 x10_leafSize; u32 x14_lightIndexCount; @@ -23,8 +23,11 @@ public: CPVSAreaSet(const u8* data, u32 len); u32 GetNumFeatures() const { return x0_numFeatures; } u32 GetNumActors() const { return xc_numActors; } + u32 Get1stLightIndex(u32 lightIdx) const { return x0_numFeatures + x8_num2ndLights + lightIdx; } + u32 Get2ndLightIndex(u32 lightIdx) const { return x0_numFeatures + lightIdx; } + bool Has2ndLayerLights() const { return x8_num2ndLights != 0; } u32 GetEntityIdByIndex(int idx) const { return x18_entityIndex[idx]; } - const CPVSVisOctree& GetVisOctree() { return x20_octree; } + const CPVSVisOctree& GetVisOctree() const { return x20_octree; } }; } diff --git a/Runtime/MP1/CSamusHud.cpp b/Runtime/MP1/CSamusHud.cpp index 1d946e7bc..9422d751b 100644 --- a/Runtime/MP1/CSamusHud.cpp +++ b/Runtime/MP1/CSamusHud.cpp @@ -759,7 +759,10 @@ void CSamusHud::UpdateHudDynamicLights(float dt, const CStateManager& mgr) { if (TCastToConstPtr fpCam = mgr.GetCameraManager()->GetCurrentCamera(mgr)) { - + zeus::CAABox camAABB(fpCam->GetTranslation() - 0.125f, fpCam->GetTranslation() + 0.125f); + if (mgr.GetPlayer().GetAreaIdAlways() == kInvalidAreaId) + return; + //x33c_lights-> } } diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index 97166ec58..6e5ec275d 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -340,6 +340,11 @@ public: MREAHeader VerifyHeader() const; TUniqueId LookupPVSUniqueID(TUniqueId id) const; s16 LookupPVSID(TUniqueId id) const; + const CPVSAreaSet* GetAreaVisSet() const { return GetPostConstructed()->xa0_pvs.get(); } + u32 Get1stPVSLightFeature(u32 lightIdx) const + { return GetAreaVisSet() ? GetAreaVisSet()->Get1stLightIndex(lightIdx) : -1; } + u32 Get2ndPVSLightFeature(u32 lightIdx) const + { return GetAreaVisSet() ? GetAreaVisSet()->Get2ndLightIndex(lightIdx) : -1; } const zeus::CTransform& GetTransform() const {return xc_transform;} const zeus::CTransform& GetInverseTransform() const {return x3c_invTransform;} diff --git a/Runtime/World/CLightParameters.hpp b/Runtime/World/CLightParameters.hpp index 138fe20a5..df13ea36f 100644 --- a/Runtime/World/CLightParameters.hpp +++ b/Runtime/World/CLightParameters.hpp @@ -5,20 +5,6 @@ #include "zeus/CColor.hpp" #include "Character/CActorLights.hpp" -static inline u32 count_1bits(u32 x) -{ - x = x - ((x >> 1) & 0x55555555); - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); - x = x + (x >> 8); - x = x + (x >> 16); - return x & 0x0000003F; -} - -static inline u32 count_0bits(u32 x) -{ - return 32 - count_1bits(x); -} - namespace urde { @@ -34,16 +20,16 @@ public: { Zero, NormalWorld, - Two, + NoShadowCast, DisableWorld }; enum class ELightRecalculationOptions { - Zero, - One, - Two, - Three + LargeFrameCount, + EightFrames, + FourFrames, + OneFrame }; private: @@ -52,54 +38,59 @@ private: EShadowTesselation xc_shadowTesselation = EShadowTesselation::Zero; float x10_d = 0.f; float x14_e = 0.f; - zeus::CColor x18_f; - bool x1c_noLights = false; - bool x1d_h = false; + zeus::CColor x18_noLightsAmbient; + bool x1c_makeLights = false; + bool x1d_ambientChannelOverflow = false; EWorldLightingOptions x20_worldLightingOptions = EWorldLightingOptions::Zero; - ELightRecalculationOptions x24_lightRecalcOpts = ELightRecalculationOptions::One; - s32 x28_k = 0; - zeus::CVector3f x2c_l; - s32 x38_m = 4; - s32 x3c_n = 4; + ELightRecalculationOptions x24_lightRecalcOpts = ELightRecalculationOptions::EightFrames; + s32 x28_layerIdx = 0; + zeus::CVector3f x2c_actorPosBias; + s32 x38_maxDynamicLights = 4; + s32 x3c_maxAreaLights = 4; public: CLightParameters() = default; - CLightParameters(bool a, float b, EShadowTesselation shadowTess, float d, float e, const zeus::CColor& f, - bool noLights, EWorldLightingOptions lightingOpts, ELightRecalculationOptions lightRecalcOpts, - const zeus::CVector3f& l, s32 m, s32 n, bool h, s32 k) - : x4_a(a), x8_b(b), xc_shadowTesselation(shadowTess), x10_d(d), x14_e(e), x18_f(f), x1c_noLights(noLights), x1d_h(h), - x20_worldLightingOptions(lightingOpts), x24_lightRecalcOpts(lightRecalcOpts), x28_k(k), x2c_l(l), x38_m(m), x3c_n(n) + CLightParameters(bool a, float b, EShadowTesselation shadowTess, float d, float e, const zeus::CColor& noLightsAmbient, + bool makeLights, EWorldLightingOptions lightingOpts, ELightRecalculationOptions lightRecalcOpts, + const zeus::CVector3f& actorPosBias, s32 maxDynamicLights, s32 maxAreaLights, bool ambChannelOverflow, s32 layerIdx) + : x4_a(a), x8_b(b), xc_shadowTesselation(shadowTess), x10_d(d), x14_e(e), x18_noLightsAmbient(noLightsAmbient), x1c_makeLights(makeLights), + x1d_ambientChannelOverflow(ambChannelOverflow), x20_worldLightingOptions(lightingOpts), x24_lightRecalcOpts(lightRecalcOpts), + x28_layerIdx(layerIdx), x2c_actorPosBias(actorPosBias), x38_maxDynamicLights(maxDynamicLights), x3c_maxAreaLights(maxAreaLights) { - if (x38_m > 4 || x38_m == -1) - x38_m = 4; - if (x3c_n > 4 || x3c_n == -1) - x3c_n = 4; + if (x38_maxDynamicLights > 4 || x38_maxDynamicLights == -1) + x38_maxDynamicLights = 4; + if (x3c_maxAreaLights > 4 || x3c_maxAreaLights == -1) + x3c_maxAreaLights = 4; } static CLightParameters None() {return CLightParameters();} static u32 GetFramesBetweenRecalculation(ELightRecalculationOptions opts) { - if (opts == ELightRecalculationOptions::Zero) + if (opts == ELightRecalculationOptions::LargeFrameCount) return 0x3FFFFFFF; - else if (opts == ELightRecalculationOptions::One) + else if (opts == ELightRecalculationOptions::EightFrames) return 8; - else if (opts == ELightRecalculationOptions::Two) + else if (opts == ELightRecalculationOptions::FourFrames) return 4; - else if (opts == ELightRecalculationOptions::Three) + else if (opts == ELightRecalculationOptions::OneFrame) return 1; return 8; } std::unique_ptr MakeActorLights() const { - if (x1c_noLights == false) + if (!x1c_makeLights) return {}; u32 updateFrames = GetFramesBetweenRecalculation(x24_lightRecalcOpts); - CActorLights* lights = new CActorLights(updateFrames, x2c_l, x1d_h, x3c_n, x38_m, - count_0bits(x28_k - 1) / 32, - count_0bits(u32(x20_worldLightingOptions) - 3) / 32, + CActorLights* lights = new CActorLights(updateFrames, x2c_actorPosBias, x38_maxDynamicLights, + x3c_maxAreaLights, x1d_ambientChannelOverflow, x28_layerIdx == 1, + x20_worldLightingOptions == EWorldLightingOptions::DisableWorld, 0.1f); - return std::unique_ptr(std::move(lights)); + if (x20_worldLightingOptions == EWorldLightingOptions::NoShadowCast) + lights->SetCastShadows(false); + if (x3c_maxAreaLights == 0) + lights->SetAmbientColor(x18_noLightsAmbient); + return std::unique_ptr(lights); } }; diff --git a/Runtime/World/CWorldLight.hpp b/Runtime/World/CWorldLight.hpp index 061dc0513..0ac247ad2 100644 --- a/Runtime/World/CWorldLight.hpp +++ b/Runtime/World/CWorldLight.hpp @@ -36,7 +36,7 @@ public: ELightType GetLightType() const; const zeus::CVector3f& GetDirection() const; const zeus::CVector3f& GetPosition() const; - bool DoesCastShadows() const; + bool DoesCastShadows() const { return x34_castShadows; } CLight GetAsCGraphicsLight() const; }; diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index f6bb50814..2f337a347 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -281,34 +281,35 @@ CLightParameters ScriptLoader::LoadLightParameters(CInputStream& in) float d = in.readFloatBig(); float e = in.readFloatBig(); - zeus::CColor col; - col.readRGBABig(in); + zeus::CColor noLightsAmbient; + noLightsAmbient.readRGBABig(in); - bool f = in.readBool(); + bool makeLights = in.readBool(); CLightParameters::EWorldLightingOptions lightOpts = CLightParameters::EWorldLightingOptions(in.readUint32Big()); CLightParameters::ELightRecalculationOptions recalcOpts = CLightParameters::ELightRecalculationOptions(in.readUint32Big()); - zeus::CVector3f vec; - vec.readBig(in); + zeus::CVector3f actorPosBias; + actorPosBias.readBig(in); - s32 w1 = -1; - s32 w2 = -1; + s32 maxDynamicLights = -1; + s32 maxAreaLights = -1; if (propCount >= 12) { - w1 = in.readUint32Big(); - w2 = in.readUint32Big(); + maxDynamicLights = in.readUint32Big(); + maxAreaLights = in.readUint32Big(); } - bool b1 = false; + bool ambientChannelOverflow = false; if (propCount >= 13) - b1 = in.readBool(); + ambientChannelOverflow = in.readBool(); - s32 w3 = 0; + s32 layerIdx = 0; if (propCount >= 14) - w3 = in.readUint32Big(); + layerIdx = in.readUint32Big(); - return CLightParameters(a, b, shadowTess, d, e, col, f, lightOpts, recalcOpts, vec, w1, w2, b1, w3); + return CLightParameters(a, b, shadowTess, d, e, noLightsAmbient, makeLights, lightOpts, recalcOpts, actorPosBias, + maxDynamicLights, maxAreaLights, ambientChannelOverflow, layerIdx); } return CLightParameters::None(); } diff --git a/visigen/VISIBuilder.cpp b/visigen/VISIBuilder.cpp index 7fab2658d..c8a55d251 100644 --- a/visigen/VISIBuilder.cpp +++ b/visigen/VISIBuilder.cpp @@ -306,6 +306,7 @@ std::vector VISIBuilder::build(const zeus::CAABox& fullAabb, size_t modelCount, const std::vector& entities, const std::vector& lights, + size_t layer2LightCount, FPercent updatePercent) { Log.report(logvisor::Info, "Started!"); @@ -338,7 +339,7 @@ std::vector VISIBuilder::build(const zeus::CAABox& fullAabb, w.writeBool(true); w.writeUint32Big(featureCount); w.writeUint32Big(lights.size()); - w.writeUint32Big(0); + w.writeUint32Big(layer2LightCount); w.writeUint32Big(entities.size()); w.writeUint32Big(leafBytesCount); w.writeUint32Big(lights.size()); diff --git a/visigen/VISIBuilder.hpp b/visigen/VISIBuilder.hpp index 0e0a50501..e7740d3fb 100644 --- a/visigen/VISIBuilder.hpp +++ b/visigen/VISIBuilder.hpp @@ -122,6 +122,7 @@ struct VISIBuilder size_t modelCount, const std::vector& entities, const std::vector& lights, + size_t layer2LightCount, FPercent updatePercent); VISIBuilder(VISIRenderer& renderer) : renderCache(renderer) {} diff --git a/visigen/VISIRenderer.cpp b/visigen/VISIRenderer.cpp index 5de3b8aed..e729a23c6 100644 --- a/visigen/VISIRenderer.cpp +++ b/visigen/VISIRenderer.cpp @@ -488,6 +488,7 @@ void VISIRenderer::Run(FPercent updatePercent) return; } + uint32_t layer2LightCount = 0; { athena::io::FileReader r(m_argv[1]); if (r.hasError()) @@ -545,6 +546,7 @@ void VISIRenderer::Run(FPercent updatePercent) } uint32_t lightCount = r.readUint32Big(); + layer2LightCount = r.readUint32Big(); m_lights.resize(lightCount); for (uint32_t i=0 ; i dataOut = builder.build(m_totalAABB, m_models.size(), - m_entities, m_lights, m_updatePercent); + m_entities, m_lights, layer2LightCount, + m_updatePercent); if (dataOut.empty()) { m_return = 1;