diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index 1702b5a9c..cd6b38c4d 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -120,6 +120,7 @@ public: float SunIntensity = 1.0f; bool AmbientOcclusion = true; bool LightBounce = true; + bool LevelWideLMDynamic = false; // Whole map has dynamic lightmaps enabled via ZDRayInfo (no need to set it per sector) TArray Portals; diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 5c893411b..fb9a699ab 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -482,6 +482,7 @@ public: uint16_t LightmapSampleDistance = 0; bool LightBounce = false; bool AmbientOcclusion = true; + bool LevelWideLMDynamic = false; // Whole map has dynamic lightmaps enabled via ZDRayInfo (no need to set it per sector) // Portal information. FDisplacementTable Displacements; diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index d2ed151b8..e52929cfc 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3253,6 +3253,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) Level->lightmaps = gameinfo.forceEnableLightmaps; Level->LightBounce = false; Level->AmbientOcclusion = true; + Level->LevelWideLMDynamic = false; // note: most of this ordering is important ForceNodeBuild = gennodes; diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index cdfd0582c..641a1d86d 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -852,6 +852,11 @@ public: Level->AmbientOcclusion = CheckBool(key); break; + case NAME_lm_dynamic: + CHECK_N(Zd | Zdt) + Level->LevelWideLMDynamic = CheckBool(key); + break; + default: CHECK_N(Zd | Zdt) if (0 == strnicmp("user_", key.GetChars(), 5)) diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 45338be82..747128273 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -22,6 +22,7 @@ #include "vm.h" #include "p_setup.h" +static void UpdateLightmapTiles(); static int InvalidateLightmap(); static void InvalidateActorLightTraceCache(); @@ -74,6 +75,16 @@ static bool RequireLightmap() return false; } +// Forces lightmap tiles update +static void UpdateLightmapTiles() +{ + for (auto& tile : level.levelMesh->Lightmap.Tiles) + { + if (!tile.NeedsInitialBake) + tile.ReceivedNewLight = true; + } +} + static int InvalidateLightmap() { int count = 0; @@ -251,6 +262,7 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap) Lightmap.SampleDistance = doomMap.LightmapSampleDistance; LightBounce = doomMap.LightBounce; AmbientOcclusion = doomMap.AmbientOcclusion; + LevelWideLMDynamic = doomMap.LevelWideLMDynamic; // HWWall and HWFlat still looks at r_viewpoint when doing calculations, // but we aren't rendering a specific viewpoint when this function gets called @@ -2717,6 +2729,14 @@ static void InvalidateActorLightTraceCache() } } +DEFINE_ACTION_FUNCTION(_Lightmap, Update) +{ + PARAM_PROLOGUE; + UpdateLightmapTiles(); + InvalidateActorLightTraceCache(); + return 0; +} + DEFINE_ACTION_FUNCTION(_Lightmap, Invalidate) { PARAM_PROLOGUE; diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index c4797c67a..f07dcb0c2 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -297,7 +297,7 @@ public: if (tile->Binding.Type == ST_UPPERSIDE || tile->Binding.Type == ST_MIDDLESIDE || tile->Binding.Type == ST_LOWERSIDE) { sector_t* sector = Level->sides[tile->Binding.TypeIndex].sector; - if (sector && (sector->Flags & SECF_LM_DYNAMIC || lm_dynlights)) + if (sector && (sector->Flags & SECF_LM_DYNAMIC || lm_dynlights || Level->LevelWideLMDynamic)) { VisibleTiles.ReceivedNewLight.Push(tile); } @@ -305,7 +305,7 @@ public: else if (tile->Binding.Type == ST_CEILING || tile->Binding.Type == ST_FLOOR) { sector_t* sector = Level->subsectors[tile->Binding.TypeIndex].sector; - if (sector && (sector->Flags & SECF_LM_DYNAMIC || lm_dynlights)) + if (sector && (sector->Flags & SECF_LM_DYNAMIC || lm_dynlights || Level->LevelWideLMDynamic)) { VisibleTiles.ReceivedNewLight.Push(tile); } diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index b3aa147d3..fbe9d2760 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -969,6 +969,9 @@ struct FRailParams struct Lightmap { + // Mark lightmap tiles for update. Prefer this over Invalidate() as the latter can crash weak graphics cards. + native static void Update(); + // Mark all lightmap surfaces for recalculation. The internal lightmapper will gradually recalculate every single lightmap surface in the level. native static void Invalidate();