From 79a7d5336423feaf8046860175f59cbb145d5765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Wed, 18 Dec 2024 04:38:35 -0300 Subject: [PATCH] auto-mark tiles for update if a lightmap light moves or changes radius or toggles --- src/playsim/a_dynlight.cpp | 117 ++++++++++++++++++++++++++++++++----- src/playsim/a_dynlight.h | 3 +- 2 files changed, 105 insertions(+), 15 deletions(-) diff --git a/src/playsim/a_dynlight.cpp b/src/playsim/a_dynlight.cpp index b8168e0a6..eaa970002 100644 --- a/src/playsim/a_dynlight.cpp +++ b/src/playsim/a_dynlight.cpp @@ -72,6 +72,41 @@ static FCRandom randLight; extern TArray StateLights; +static void MarkTilesForUpdate(FLevelLocals * Level, const TArrayView &tiles) +{ + for(int i : tiles) + { + if(i >= 0) + { + Level->levelMesh->Lightmap.Tiles[i].NeedsUpdate = true; + } + } +} + +static void MarkTilesForUpdate(FLevelLocals * Level, FLightNode * touching_sides, FLightNode * touching_sector) +{ + if(Level->levelMesh) + { + while(touching_sides) + { + MarkTilesForUpdate(Level, touching_sides->targLine->LightmapTiles); + + touching_sides = touching_sides->nextTarget; + } + + while(touching_sector) + { + for(subsector_t * ss : static_cast(touching_sector->targ)->subsectors) + { + MarkTilesForUpdate(Level, ss->LightmapTiles[0]); + MarkTilesForUpdate(Level, ss->LightmapTiles[1]); + } + + touching_sector = touching_sector->nextTarget; + } + } +} + //========================================================================== // // @@ -132,6 +167,7 @@ void AttachLight(AActor *self) light->target = self; light->mShadowmapIndex = 1024; light->m_active = false; + light->wasactive = false; light->visibletoplayer = true; light->lighttype = (uint8_t)self->IntVar(NAME_lighttype); self->AttachedLights.Push(light); @@ -252,6 +288,7 @@ void FDynamicLight::Activate() } + //========================================================================== // // [TS] @@ -270,22 +307,29 @@ void FDynamicLight::Tick() if (owned) { - if (!target->state || !target->ShouldRenderLocally()) - { - Deactivate(); - return; - } - if (target->flags & MF_UNMORPHED) + if (!target->state || !target->ShouldRenderLocally() || (target->flags & MF_UNMORPHED)) { m_active = false; - return; } - visibletoplayer = target->IsVisibleToPlayer(); // cache this value for the renderer to speed up calculations. + else + { + visibletoplayer = target->IsVisibleToPlayer(); // cache this value for the renderer to speed up calculations. + } } - // Don't bother if the light won't be shown - if (!IsActive()) return; + bool markTiles = (Trace() && Level->levelMesh); + // Don't bother if the light won't be shown + if (!IsActive()) + { + if(markTiles && m_active != wasactive) + { + MarkTilesForUpdate(Level, touching_sides, touching_sector); + } + wasactive = m_active; + return; + } + // I am doing this with a type field so that I can dynamically alter the type of light // without having to create or maintain multiple objects. switch(lighttype) @@ -376,7 +420,15 @@ void FDynamicLight::Tick() { lightStrength = LightCalcStrength(m_currentRadius); } - UpdateLocation(); + + bool updated = UpdateLocation(); + + if(!updated && markTiles && m_active != wasactive) + { + MarkTilesForUpdate(Level, touching_sides, touching_sector); + } + + wasactive = m_active; } @@ -387,7 +439,7 @@ void FDynamicLight::Tick() // // //========================================================================== -void FDynamicLight::UpdateLocation() +bool FDynamicLight::UpdateLocation() { double oldx= X(); double oldy= Y(); @@ -434,8 +486,11 @@ void FDynamicLight::UpdateLocation() { //Update the light lists LinkLight(); + return true; } } + + return false; } //============================================================================= @@ -566,6 +621,8 @@ void FDynamicLight::CollectWithinRadius(const DVector3 &opos, FSection *section, collected_ss.Push({ section, opos }); section->validcount = dl_validcount; + bool markTiles = (Trace() && Level->levelMesh); + bool hitonesidedback = false; for (unsigned i = 0; i < collected_ss.Size(); i++) { @@ -574,6 +631,14 @@ void FDynamicLight::CollectWithinRadius(const DVector3 &opos, FSection *section, touching_sector = AddLightNode(§ion->lighthead, section, this, touching_sector); + if(markTiles) + { + for(subsector_t * ss : section->subsectors) + { + MarkTilesForUpdate(Level, ss->LightmapTiles[0]); + MarkTilesForUpdate(Level, ss->LightmapTiles[1]); + } + } auto processSide = [&](side_t *sidedef, const vertex_t *v1, const vertex_t *v2) { @@ -585,6 +650,10 @@ void FDynamicLight::CollectWithinRadius(const DVector3 &opos, FSection *section, { linedef->validcount = ::validcount; touching_sides = AddLightNode(&sidedef->lighthead, sidedef, this, touching_sides); + if(markTiles) + { + MarkTilesForUpdate(Level, sidedef->LightmapTiles); + } } else if (linedef->sidedef[0] == sidedef && linedef->sidedef[1] == nullptr) { @@ -747,8 +816,28 @@ void FDynamicLight::LinkLight() //========================================================================== void FDynamicLight::UnlinkLight () { - while (touching_sides) touching_sides = DeleteLightNode(touching_sides); - while (touching_sector) touching_sector = DeleteLightNode(touching_sector); + bool markTiles = (Trace() && Level->levelMesh); + + while (touching_sides) + { + if(markTiles) + { + MarkTilesForUpdate(Level, touching_sides->targLine->LightmapTiles); + } + touching_sides = DeleteLightNode(touching_sides); + } + while (touching_sector) + { + if(markTiles) + { + for(subsector_t * ss : static_cast(touching_sector->targ)->subsectors) + { + MarkTilesForUpdate(Level, ss->LightmapTiles[0]); + MarkTilesForUpdate(Level, ss->LightmapTiles[1]); + } + } + touching_sector = DeleteLightNode(touching_sector); + } shadowmapped = false; } diff --git a/src/playsim/a_dynlight.h b/src/playsim/a_dynlight.h index 4cd010170..98f45eb7e 100644 --- a/src/playsim/a_dynlight.h +++ b/src/playsim/a_dynlight.h @@ -254,7 +254,7 @@ struct FDynamicLight double Z() const { return Pos.Z; } void Tick(); - void UpdateLocation(); + bool UpdateLocation(); void LinkLight(); void UnlinkLight(); void ReleaseLight(); @@ -292,6 +292,7 @@ public: int m_lastUpdate; int mShadowmapIndex; bool m_active; + bool wasactive; bool visibletoplayer; bool shadowmapped; uint8_t lighttype;