From da224d492aa53468db429b7b7b2884ee6a7c1c2b Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 13 Mar 2022 15:14:11 -0400 Subject: [PATCH] CCubeRenderer: Implement ActivateLightsForModel & PrepareDynamicLights --- Runtime/Graphics/CCubeRenderer.cpp | 78 +++++++++++++++++++++++++++++- Runtime/Graphics/CLight.hpp | 2 +- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index eac9349fe..c834f5ac7 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -501,7 +501,65 @@ void CCubeRenderer::HandleUnsortedModelWireframe(CAreaListItem* areaItem, CCubeM } constexpr bool TestBit(const u32* words, size_t bit) { return (words[bit / 32] & (1U << (bit & 0x1f))) != 0; } -void CCubeRenderer::ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model) {} + +void CCubeRenderer::ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model) { + constexpr u32 LightCount = 4; + GX::LightMask lightMask; + + if (!x300_dynamicLights.empty()) { + std::array addedLights{}; + std::array lightRads{-1.f, -1.f, -1.f, -1.f}; + + u32 lightOctreeWordCount = 0; + const u32* lightOctreeWords = nullptr; + if (areaItem != nullptr && model.GetIndex() != UINT32_MAX) { + lightOctreeWordCount = areaItem->x4_octTree->x14_bitmapWordCount; + lightOctreeWords = areaItem->x1c_lightOctreeWords.data(); + } + + u32 lightIdx = 0; + for (const auto& light : x300_dynamicLights) { + if (lightOctreeWords == nullptr || TestBit(lightOctreeWords, model.GetIndex())) { + bool loaded = false; + const float radius = + model.GetBounds().intersectionRadius(zeus::CSphere(light.GetPosition(), light.GetRadius())); + + if (lightIdx > 0) { + for (u32 i = 0; i < lightIdx; ++i) { + if (addedLights[i] == light.GetId()) { + if (radius >= 0.f && radius < lightRads[i]) { + lightRads[i] = radius; + CGraphics::LoadLight(i, light); + loaded = true; + } + break; + } + } + } + + if (!loaded) { + lightRads[lightIdx] = radius; + if (radius >= 0.f) { + CGraphics::LoadLight(lightIdx, light); + addedLights[lightIdx] = light.GetId(); + lightMask.set(lightIdx); + ++lightIdx; + } + } + } + + lightOctreeWords += lightOctreeWordCount; + } + } + + if (lightMask.any()) { + CGraphics::SetLightState(lightMask); + CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite); + } else { + CGraphics::DisableAllLights(); + CGX::SetChanAmbColor(CGX::EChannelId::Channel0, CGX::GetChanAmbColor(CGX::EChannelId::Channel0)); + } +} void CCubeRenderer::AddParticleGen(CParticleGen& gen) { auto bounds = gen.GetBounds(); @@ -777,7 +835,23 @@ void CCubeRenderer::SetGXRegister1Color(const zeus::CColor& color) { GXSetTevCol void CCubeRenderer::SetWorldLightFadeLevel(float level) { x2fc_tevReg1Color = zeus::CColor(level, level, level, 1.f); } void CCubeRenderer::PrepareDynamicLights(const std::vector& lights) { - // TODO + x300_dynamicLights = lights; + + for (CAreaListItem& area : x1c_areaListItems) { + if (const CAreaRenderOctTree* arot = area.x4_octTree) { + area.x1c_lightOctreeWords.clear(); + area.x1c_lightOctreeWords.resize(arot->x14_bitmapWordCount * lights.size()); + u32* wordPtr = area.x1c_lightOctreeWords.data(); + for (const CLight& light : lights) { + float radius = light.GetRadius(); + zeus::CVector3f vMin = light.GetPosition() - radius; + zeus::CVector3f vMax = light.GetPosition() + radius; + zeus::CAABox aabb(vMin, vMax); + arot->FindOverlappingModels(wordPtr, aabb); + wordPtr += arot->x14_bitmapWordCount; + } + } + } } void CCubeRenderer::AllocatePhazonSuitMaskTexture() { diff --git a/Runtime/Graphics/CLight.hpp b/Runtime/Graphics/CLight.hpp index 4321de1b4..ca5556881 100644 --- a/Runtime/Graphics/CLight.hpp +++ b/Runtime/Graphics/CLight.hpp @@ -88,7 +88,7 @@ public: float GetAngleAttenuationQuadratic() const { return x38_angleQ; } ELightType GetType() const { return x1c_type; } - + u32 GetId() const { return x40_lightId; } float GetIntensity() const; float GetRadius() const; const zeus::CColor& GetColor() const { return x18_color; }