#include "Render/DescentLightPool.h" #include "Core/Tuning/DescentTune_Look.h" #include "DescentUnits.h" #include "Components/PointLightComponent.h" #include "GameFramework/Actor.h" namespace LTune = Descent::Tune::Look; UDescentLightPool::UDescentLightPool() { PrimaryComponentTick.bCanEverTick = false; } void UDescentLightPool::BeginPlay() { Super::BeginPlay(); AActor* Owner = GetOwner(); if (!Owner || Lights.Num() > 0) { return; } for (int32 I = 0; I < LTune::LightPoolSize; ++I) { UPointLightComponent* L = NewObject(Owner, NAME_None, RF_Transient); L->SetMobility(EComponentMobility::Movable); L->bUseInverseSquaredFalloff = false; L->SetLightFalloffExponent(LTune::LightFalloffExponent); L->SetCastShadows(false); L->SetVolumetricScatteringIntensity(static_cast(LTune::LightPoolScatter)); L->SetVisibility(false); L->SetupAttachment(Owner->GetRootComponent()); L->RegisterComponent(); Lights.Add(L); } } void UDescentLightPool::Select(const TArray& Reqs, const FVector& Cam, int32 MaxLights, double MaxScore, TArray& Out) { struct FScored { int32 Index; double Score; }; TArray Scored; for (int32 I = 0; I < Reqs.Num(); ++I) { const double R = FMath::Max(0.01, static_cast(Reqs[I].RadiusM)); const double D = FVector::Dist(Cam, Reqs[I].PositionUU) / Descent::UUPerMetre; const double Score = (D * D) / (R * R) - Reqs[I].Priority; if (Score < MaxScore) { Scored.Add({ I, Score }); } } // Stable on ties: lower index first, so the winners never depend on sort internals. Scored.Sort([](const FScored& A, const FScored& B) { return A.Score < B.Score || (A.Score == B.Score && A.Index < B.Index); }); Out.Reset(); for (int32 I = 0; I < Scored.Num() && I < MaxLights; ++I) { Out.Add(Scored[I].Index); } } void UDescentLightPool::Commit(const FVector& CameraUU) { TArray Win; Select(Requests, CameraUU, Lights.Num(), LTune::LightPoolMaxScore, Win); NumRequestsSeen = Requests.Num(); for (int32 I = 0; I < Lights.Num(); ++I) { UPointLightComponent* L = Lights[I]; if (!L) { continue; } if (I < Win.Num()) { const FDescentLightRequest& R = Requests[Win[I]]; L->SetWorldLocation(R.PositionUU); L->SetLightColor(R.Color); L->SetIntensity(R.Intensity); L->SetAttenuationRadius(static_cast(Descent::MetresToUU(R.RadiusM))); L->SetVisibility(true); } else if (L->IsVisible()) { L->SetVisibility(false); } } NumLitLights = Win.Num(); Requests.Reset(); }