Split level mesh surface from lightmap tiles as we have multiple surfaces per tile

This commit is contained in:
Magnus Norddahl 2023-12-17 14:17:22 +01:00
commit 48b6a7ec46
19 changed files with 446 additions and 597 deletions

View file

@ -43,10 +43,10 @@ ADD_STAT(lightmap)
}
uint32_t atlasPixelCount = levelMesh->StaticMesh->AtlasPixelCount();
auto stats = levelMesh->GatherSurfacePixelStats();
auto stats = levelMesh->GatherTilePixelStats();
out.Format("Surfaces: %u (sky: %u, awaiting updates: %u)\nSurface pixel area to update: %u\nSurface pixel area: %u\nAtlas pixel area: %u\nAtlas efficiency: %.4f%%",
stats.surfaces.total, stats.surfaces.sky, std::max(stats.surfaces.dirty - stats.surfaces.sky, (uint32_t)0),
out.Format("Surfaces: %u (awaiting updates: %u)\nSurface pixel area to update: %u\nSurface pixel area: %u\nAtlas pixel area: %u\nAtlas efficiency: %.4f%%",
stats.tiles.total, stats.tiles.dirty,
stats.pixels.dirty,
stats.pixels.total,
atlasPixelCount,
@ -67,13 +67,13 @@ CCMD(invalidatelightmap)
if (!RequireLightmap()) return;
int count = 0;
for (auto& surface : static_cast<DoomLevelSubmesh*>(level.levelMesh->StaticMesh.get())->Surfaces)
for (auto& tile : level.levelMesh->StaticMesh->LightmapTiles)
{
if (!surface.NeedsUpdate)
if (!tile.NeedsUpdate)
++count;
surface.NeedsUpdate = true;
tile.NeedsUpdate = true;
}
Printf("Marked %d out of %d surfaces for update.\n", count, level.levelMesh->StaticMesh->GetSurfaceCount());
Printf("Marked %d out of %d tiles for update.\n", count, level.levelMesh->StaticMesh->LightmapTiles.Size());
}
void PrintSurfaceInfo(const DoomLevelMeshSurface* surface)
@ -83,10 +83,14 @@ void PrintSurfaceInfo(const DoomLevelMeshSurface* surface)
auto gameTexture = surface->Texture;
Printf("Surface %d (%p)\n Type: %d, TypeIndex: %d, ControlSector: %d\n", surface->Submesh->GetSurfaceIndex(surface), surface, surface->Type, surface->TypeIndex, surface->ControlSector ? surface->ControlSector->Index() : -1);
Printf(" Atlas page: %d, x:%d, y:%d\n", surface->AtlasTile.ArrayIndex, surface->AtlasTile.X, surface->AtlasTile.Y);
Printf(" Pixels: %dx%d (area: %d)\n", surface->AtlasTile.Width, surface->AtlasTile.Height, surface->AtlasTile.Area());
Printf(" Sample dimension: %d\n", surface->SampleDimension);
Printf(" Needs update?: %d\n", surface->NeedsUpdate);
if (surface->LightmapTileIndex >= 0)
{
LightmapTile* tile = &surface->Submesh->LightmapTiles[surface->LightmapTileIndex];
Printf(" Atlas page: %d, x:%d, y:%d\n", tile->AtlasLocation.ArrayIndex, tile->AtlasLocation.X, tile->AtlasLocation.Y);
Printf(" Pixels: %dx%d (area: %d)\n", tile->AtlasLocation.Width, tile->AtlasLocation.Height, tile->AtlasLocation.Area());
Printf(" Sample dimension: %d\n", tile->SampleDimension);
Printf(" Needs update?: %d\n", tile->NeedsUpdate);
}
Printf(" Always update?: %d\n", surface->AlwaysUpdate);
Printf(" Sector group: %d\n", surface->SectorGroup);
Printf(" Texture: '%s'\n", gameTexture ? gameTexture->GetName().GetChars() : "<nullptr>");
@ -160,11 +164,6 @@ bool DoomLevelMesh::TraceSky(const FVector3& start, FVector3 direction, float di
return surface && surface->IsSky;
}
void DoomLevelMesh::PackLightmapAtlas()
{
static_cast<DoomLevelSubmesh*>(StaticMesh.get())->PackLightmapAtlas(0);
}
int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize)
{
FLightNode* node = GetSurfaceLightNode(static_cast<const DoomLevelMeshSurface*>(surface));
@ -317,11 +316,16 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen
{
const auto& surface = submesh->Surfaces[index];
fprintf(f, "o Surface[%d] %s %d%s\n", index, name(surface.Type), surface.TypeIndex, surface.IsSky ? " sky" : "");
fprintf(f, "usemtl lightmap%d\n", surface.AtlasTile.ArrayIndex);
if (surface.AtlasTile.ArrayIndex > highestUsedAtlasPage)
if (surface.LightmapTileIndex >= 0)
{
highestUsedAtlasPage = surface.AtlasTile.ArrayIndex;
auto& tile = submesh->LightmapTiles[surface.LightmapTileIndex];
fprintf(f, "usemtl lightmap%d\n", tile.AtlasLocation.ArrayIndex);
if (tile.AtlasLocation.ArrayIndex > highestUsedAtlasPage)
{
highestUsedAtlasPage = tile.AtlasLocation.ArrayIndex;
}
}
}
}

View file

@ -13,7 +13,6 @@ public:
void BeginFrame(FLevelLocals& doomMap);
bool TraceSky(const FVector3& start, FVector3 direction, float dist);
void PackLightmapAtlas();
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const;
void BuildSectorGroups(const FLevelLocals& doomMap);

View file

@ -32,9 +32,9 @@ DoomLevelSubmesh::DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, b
LinkSurfaces(doomMap);
CreateIndexes();
SetupLightmapUvs(doomMap);
BuildTileSurfaceLists();
UpdateCollision();
PackLightmapAtlas(0);
}
}
@ -48,7 +48,6 @@ void DoomLevelSubmesh::Update(FLevelLocals& doomMap, int lightmapStartIndex)
LinkSurfaces(doomMap);
CreateIndexes();
SetupLightmapUvs(doomMap);
BuildTileSurfaceLists();
UpdateCollision();
@ -86,6 +85,7 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
}
MeshBuilder state;
std::map<LightmapTileBinding, int> bindings;
// Create surface objects for all sides
for (unsigned int i = 0; i < doomMap.sides.Size(); i++)
@ -115,19 +115,19 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
state.EnableTexture(true);
state.EnableBrightmap(true);
state.AlphaFunc(Alpha_GEqual, 0.f);
CreateWallSurface(side, disp, state, result.list, false, true);
CreateWallSurface(side, disp, state, bindings, result.list, false, true);
for (HWWall& portal : result.portals)
{
Portals.Push(portal);
}
CreateWallSurface(side, disp, state, result.portals, true, false);
CreateWallSurface(side, disp, state, bindings, result.portals, true, false);
// final pass: translucent stuff
state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
state.SetRenderStyle(STYLE_Translucent);
CreateWallSurface(side, disp, state, result.translucent, false, true);
CreateWallSurface(side, disp, state, bindings, result.translucent, false, true);
state.AlphaFunc(Alpha_GEqual, 0.f);
state.SetRenderStyle(STYLE_Normal);
}
@ -154,24 +154,29 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
state.ClearDepthBias();
state.EnableTexture(true);
state.EnableBrightmap(true);
CreateFlatSurface(disp, state, result.list);
CreateFlatSurface(disp, state, bindings, result.list);
CreateFlatSurface(disp, state, result.portals, true);
CreateFlatSurface(disp, state, bindings, result.portals, true);
// final pass: translucent stuff
state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
state.SetRenderStyle(STYLE_Translucent);
CreateFlatSurface(disp, state, result.translucentborder);
CreateFlatSurface(disp, state, bindings, result.translucentborder);
state.SetDepthMask(false);
CreateFlatSurface(disp, state, result.translucent);
CreateFlatSurface(disp, state, bindings, result.translucent);
state.AlphaFunc(Alpha_GEqual, 0.f);
state.SetDepthMask(true);
state.SetRenderStyle(STYLE_Normal);
}
}
for (auto& tile : LightmapTiles)
{
SetupTileTransform(LMTextureSize, LMTextureSize, tile);
}
}
void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray<HWWall>& list, bool isSky, bool translucent)
void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWWall>& list, bool isSky, bool translucent)
{
for (HWWall& wallpart : list)
{
@ -254,11 +259,74 @@ void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, M
surf.PipelineID = pipelineID;
surf.PortalIndex = isSky ? LevelMesh->linePortals[side->linedef->Index()] : 0;
surf.IsSky = isSky;
surf.Bounds = GetBoundsFromSurface(surf);
surf.LightmapTileIndex = AddSurfaceToTile(surf, bindings);
Surfaces.Push(surf);
}
}
void DoomLevelSubmesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray<HWFlat>& list, bool isSky)
int DoomLevelSubmesh::AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map<LightmapTileBinding, int>& bindings)
{
LightmapTileBinding binding;
binding.Type = surf.Type;
binding.TypeIndex = surf.TypeIndex;
binding.ControlSector = surf.ControlSector ? surf.ControlSector->Index() : (int)0xffffffffUL;
auto it = bindings.find(binding);
if (it != bindings.end())
{
int index = it->second;
LightmapTile& tile = LightmapTiles[index];
tile.Bounds.min.X = std::min(tile.Bounds.min.X, surf.Bounds.min.X);
tile.Bounds.min.Y = std::min(tile.Bounds.min.Y, surf.Bounds.min.Y);
tile.Bounds.min.Z = std::min(tile.Bounds.min.Z, surf.Bounds.min.Z);
tile.Bounds.max.X = std::max(tile.Bounds.max.X, surf.Bounds.max.X);
tile.Bounds.max.Y = std::max(tile.Bounds.max.Y, surf.Bounds.max.Y);
tile.Bounds.max.Z = std::max(tile.Bounds.max.Z, surf.Bounds.max.Z);
return index;
}
else
{
int index = LightmapTiles.Size();
LightmapTile tile;
tile.Binding = binding;
tile.Bounds = surf.Bounds;
tile.Plane = surf.Plane;
tile.SampleDimension = GetSampleDimension(surf);
LightmapTiles.Push(tile);
bindings[binding] = index;
return index;
}
}
int DoomLevelSubmesh::GetSampleDimension(const DoomLevelMeshSurface& surf)
{
uint16_t sampleDimension = 0; // To do: something seems to have gone missing with the sample dimension!
if (sampleDimension <= 0)
{
sampleDimension = LightmapSampleDistance;
}
sampleDimension = uint16_t(max(int(roundf(float(sampleDimension) / max(1.0f / 4, float(lm_scale)))), 1));
// Round to nearest power of two
uint32_t n = uint16_t(sampleDimension);
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n = (n + 1) >> 1;
sampleDimension = uint16_t(n) ? uint16_t(n) : uint16_t(0xFFFF);
return sampleDimension;
}
void DoomLevelSubmesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWFlat>& list, bool isSky)
{
for (HWFlat& flatpart : list)
{
@ -355,6 +423,8 @@ void DoomLevelSubmesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& st
surf.Subsector = sub;
surf.MeshLocation.StartVertIndex = startVertIndex;
surf.MeshLocation.NumVerts = sub->numlines;
surf.Bounds = GetBoundsFromSurface(surf);
surf.LightmapTileIndex = AddSurfaceToTile(surf, bindings);
Surfaces.Push(surf);
}
}
@ -553,54 +623,52 @@ bool DoomLevelSubmesh::IsDegenerate(const FVector3 &v0, const FVector3 &v1, cons
return crosslengthsqr <= 1.e-6f;
}
void DoomLevelSubmesh::SetupLightmapUvs(FLevelLocals& doomMap)
{
LMTextureSize = 1024;
for (auto& surface : Surfaces)
{
SetupTileTransform(LMTextureSize, LMTextureSize, surface);
}
}
void DoomLevelSubmesh::PackLightmapAtlas(int lightmapStartIndex)
{
std::vector<LevelMeshSurface*> sortedSurfaces;
sortedSurfaces.reserve(Surfaces.Size());
std::vector<LightmapTile*> sortedTiles;
sortedTiles.reserve(LightmapTiles.Size());
for (auto& surface : Surfaces)
for (auto& tile : LightmapTiles)
{
sortedSurfaces.push_back(&surface);
sortedTiles.push_back(&tile);
}
std::sort(sortedSurfaces.begin(), sortedSurfaces.end(), [](LevelMeshSurface* a, LevelMeshSurface* b) { return a->AtlasTile.Height != b->AtlasTile.Height ? a->AtlasTile.Height > b->AtlasTile.Height : a->AtlasTile.Width > b->AtlasTile.Width; });
std::sort(sortedTiles.begin(), sortedTiles.end(), [](LightmapTile* a, LightmapTile* b) { return a->AtlasLocation.Height != b->AtlasLocation.Height ? a->AtlasLocation.Height > b->AtlasLocation.Height : a->AtlasLocation.Width > b->AtlasLocation.Width; });
RectPacker packer(LMTextureSize, LMTextureSize, RectPacker::Spacing(0));
for (LevelMeshSurface* surf : sortedSurfaces)
for (LightmapTile* tile : sortedTiles)
{
int sampleWidth = surf->AtlasTile.Width;
int sampleHeight = surf->AtlasTile.Height;
int sampleWidth = tile->AtlasLocation.Width;
int sampleHeight = tile->AtlasLocation.Height;
auto result = packer.insert(sampleWidth, sampleHeight);
int x = result.pos.x, y = result.pos.y;
surf->AtlasTile.X = x;
surf->AtlasTile.Y = y;
surf->AtlasTile.ArrayIndex = lightmapStartIndex + (int)result.pageIndex;
// calculate final texture coordinates
for (int i = 0; i < (int)surf->MeshLocation.NumVerts; i++)
{
auto& vertex = Mesh.Vertices[surf->MeshLocation.StartVertIndex + i];
vertex.lu = (vertex.lu + x) / (float)LMTextureSize;
vertex.lv = (vertex.lv + y) / (float)LMTextureSize;
vertex.lindex = (float)surf->AtlasTile.ArrayIndex;
}
tile->AtlasLocation.X = x;
tile->AtlasLocation.Y = y;
tile->AtlasLocation.ArrayIndex = lightmapStartIndex + (int)result.pageIndex;
}
LMTextureCount = (int)packer.getNumPages();
// Calculate final texture coordinates
for (auto& surface : Surfaces)
{
if (surface.LightmapTileIndex >= 0)
{
const LightmapTile& tile = LightmapTiles[surface.LightmapTileIndex];
for (int i = 0; i < surface.MeshLocation.NumVerts; i++)
{
FVector3 tDelta = Mesh.Vertices[surface.MeshLocation.StartVertIndex + i].fPos() - tile.Transform.TranslateWorldToLocal;
auto& vertex = Mesh.Vertices[surface.MeshLocation.StartVertIndex + i];
vertex.lu = (tile.AtlasLocation.X + (tDelta | tile.Transform.ProjLocalToU)) / (float)LMTextureSize;
vertex.lv = (tile.AtlasLocation.Y + (tDelta | tile.Transform.ProjLocalToV)) / (float)LMTextureSize;
vertex.lindex = (float)tile.AtlasLocation.ArrayIndex;
}
}
}
#if 0 // Debug atlas tile locations:
uint16_t colors[30] =
{
@ -617,21 +685,20 @@ void DoomLevelSubmesh::PackLightmapAtlas(int lightmapStartIndex)
};
LMTextureData.Resize(LMTextureSize * LMTextureSize * LMTextureCount * 3);
uint16_t* pixels = LMTextureData.Data();
for (DoomLevelMeshSurface& surf : Surfaces)
for (LightmapTile& tile : LightmapTiles)
{
surf.AlwaysUpdate = false;
surf.NeedsUpdate = false;
tile.NeedsUpdate = false;
int index = surf.Side ? surf.Side->Index() : (surf.Subsector && surf.Subsector->sector ? surf.Subsector->sector->Index() : 0);
int index = tile.Binding.TypeIndex;
uint16_t* color = colors + (index % 10) * 3;
int x = surf.AtlasTile.X;
int y = surf.AtlasTile.Y;
int w = surf.AtlasTile.Width;
int h = surf.AtlasTile.Height;
int x = tile.AtlasLocation.X;
int y = tile.AtlasLocation.Y;
int w = tile.AtlasLocation.Width;
int h = tile.AtlasLocation.Height;
for (int yy = y; yy < y + h; yy++)
{
uint16_t* line = pixels + surf.AtlasTile.ArrayIndex * LMTextureSize * LMTextureSize + yy * LMTextureSize * 3;
uint16_t* line = pixels + tile.AtlasLocation.ArrayIndex * LMTextureSize * LMTextureSize + yy * LMTextureSize * 3;
for (int xx = x; xx < x + w; xx++)
{
line[xx * 3] = color[0];
@ -640,35 +707,31 @@ void DoomLevelSubmesh::PackLightmapAtlas(int lightmapStartIndex)
}
}
}
for (DoomLevelMeshSurface& surf : Surfaces)
{
surf.AlwaysUpdate = false;
}
#endif
}
BBox DoomLevelSubmesh::GetBoundsFromSurface(const LevelMeshSurface& surface) const
{
constexpr float M_INFINITY = 1e30f; // TODO cleanup
FVector3 low(M_INFINITY, M_INFINITY, M_INFINITY);
FVector3 hi(-M_INFINITY, -M_INFINITY, -M_INFINITY);
BBox bounds;
bounds.Clear();
for (int i = int(surface.MeshLocation.StartVertIndex); i < int(surface.MeshLocation.StartVertIndex) + surface.MeshLocation.NumVerts; i++)
{
for (int j = 0; j < 3; j++)
{
if (Mesh.Vertices[i].fPos()[j] < low[j])
if (Mesh.Vertices[i].fPos()[j] < bounds.min[j])
{
low[j] = Mesh.Vertices[i].fPos()[j];
bounds.min[j] = Mesh.Vertices[i].fPos()[j];
}
if (Mesh.Vertices[i].fPos()[j] > hi[j])
if (Mesh.Vertices[i].fPos()[j] > bounds.max[j])
{
hi[j] = Mesh.Vertices[i].fPos()[j];
bounds.max[j] = Mesh.Vertices[i].fPos()[j];
}
}
}
BBox bounds;
bounds.Clear();
bounds.min = low;
bounds.max = hi;
return bounds;
}
@ -691,41 +754,22 @@ DoomLevelSubmesh::PlaneAxis DoomLevelSubmesh::BestAxis(const FVector4& p)
return AXIS_XY;
}
void DoomLevelSubmesh::SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface)
void DoomLevelSubmesh::SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LightmapTile& tile)
{
BBox bounds = GetBoundsFromSurface(surface);
surface.Bounds = bounds;
if (surface.SampleDimension <= 0)
{
surface.SampleDimension = LightmapSampleDistance;
}
surface.SampleDimension = uint16_t(max(int(roundf(float(surface.SampleDimension) / max(1.0f / 4, float(lm_scale)))), 1));
{
// Round to nearest power of two
uint32_t n = uint16_t(surface.SampleDimension);
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n = (n + 1) >> 1;
surface.SampleDimension = uint16_t(n) ? uint16_t(n) : uint16_t(0xFFFF);
}
BBox bounds = tile.Bounds;
// round off dimensions
FVector3 roundedSize;
for (int i = 0; i < 3; i++)
{
bounds.min[i] = surface.SampleDimension * (floor(bounds.min[i] / surface.SampleDimension) - 1);
bounds.max[i] = surface.SampleDimension * (ceil(bounds.max[i] / surface.SampleDimension) + 1);
roundedSize[i] = (bounds.max[i] - bounds.min[i]) / surface.SampleDimension;
bounds.min[i] = tile.SampleDimension * (floor(bounds.min[i] / tile.SampleDimension) - 1);
bounds.max[i] = tile.SampleDimension * (ceil(bounds.max[i] / tile.SampleDimension) + 1);
roundedSize[i] = (bounds.max[i] - bounds.min[i]) / tile.SampleDimension;
}
FVector3 tCoords[2] = { FVector3(0.0f, 0.0f, 0.0f), FVector3(0.0f, 0.0f, 0.0f) };
PlaneAxis axis = BestAxis(surface.Plane);
PlaneAxis axis = BestAxis(tile.Plane);
int width;
int height;
@ -735,22 +779,22 @@ void DoomLevelSubmesh::SetupTileTransform(int lightMapTextureWidth, int lightMap
case AXIS_YZ:
width = (int)roundedSize.Y;
height = (int)roundedSize.Z;
tCoords[0].Y = 1.0f / surface.SampleDimension;
tCoords[1].Z = 1.0f / surface.SampleDimension;
tCoords[0].Y = 1.0f / tile.SampleDimension;
tCoords[1].Z = 1.0f / tile.SampleDimension;
break;
case AXIS_XZ:
width = (int)roundedSize.X;
height = (int)roundedSize.Z;
tCoords[0].X = 1.0f / surface.SampleDimension;
tCoords[1].Z = 1.0f / surface.SampleDimension;
tCoords[0].X = 1.0f / tile.SampleDimension;
tCoords[1].Z = 1.0f / tile.SampleDimension;
break;
case AXIS_XY:
width = (int)roundedSize.X;
height = (int)roundedSize.Y;
tCoords[0].X = 1.0f / surface.SampleDimension;
tCoords[1].Y = 1.0f / surface.SampleDimension;
tCoords[0].X = 1.0f / tile.SampleDimension;
tCoords[1].Y = 1.0f / tile.SampleDimension;
break;
}
@ -768,18 +812,10 @@ void DoomLevelSubmesh::SetupTileTransform(int lightMapTextureWidth, int lightMap
height = (lightMapTextureHeight - 2);
}
surface.TileTransform.TranslateWorldToLocal = bounds.min;
surface.TileTransform.ProjLocalToU = tCoords[0];
surface.TileTransform.ProjLocalToV = tCoords[1];
tile.Transform.TranslateWorldToLocal = bounds.min;
tile.Transform.ProjLocalToU = tCoords[0];
tile.Transform.ProjLocalToV = tCoords[1];
for (int i = 0; i < surface.MeshLocation.NumVerts; i++)
{
FVector3 tDelta = Mesh.Vertices[surface.MeshLocation.StartVertIndex + i].fPos() - surface.TileTransform.TranslateWorldToLocal;
Mesh.Vertices[surface.MeshLocation.StartVertIndex + i].lu = (tDelta | surface.TileTransform.ProjLocalToU);
Mesh.Vertices[surface.MeshLocation.StartVertIndex + i].lv = (tDelta | surface.TileTransform.ProjLocalToV);
}
surface.AtlasTile.Width = width;
surface.AtlasTile.Height = height;
tile.AtlasLocation.Width = width;
tile.AtlasLocation.Height = height;
}

View file

@ -9,6 +9,7 @@
#include "bounds.h"
#include <dp_rect_pack.h>
#include <set>
#include <map>
typedef dp::rect_pack::RectPacker<int> RectPacker;
@ -60,12 +61,10 @@ private:
void SetSubsectorLightmap(DoomLevelMeshSurface* surface);
void SetSideLightmap(DoomLevelMeshSurface* surface);
void SetupLightmapUvs(FLevelLocals& doomMap);
void CreateIndexes();
void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray<HWWall>& list, bool isSky, bool translucent);
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray<HWFlat>& list, bool isSky = false);
void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWWall>& list, bool isSky, bool translucent);
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWFlat>& list, bool isSky = false);
static FVector4 ToPlane(const FVector3& pt1, const FVector3& pt2, const FVector3& pt3)
{
@ -100,7 +99,9 @@ private:
static PlaneAxis BestAxis(const FVector4& p);
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
void SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface);
void SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LightmapTile& tile);
int AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map<LightmapTileBinding, int>& bindings);
int GetSampleDimension(const DoomLevelMeshSurface& surf);
static bool IsDegenerate(const FVector3& v0, const FVector3& v1, const FVector3& v2);

View file

@ -129,7 +129,7 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
hudsprites.Clear();
Coronas.Clear();
Fogballs.Clear();
VisibleSurfaces.Clear();
VisibleTiles.Clear();
vpIndex = 0;
// Fullbright information needs to be propagated from the main view.
@ -620,20 +620,20 @@ void HWDrawInfo::PutWallPortal(HWWall wall, FRenderState& state)
void HWDrawInfo::UpdateLightmaps()
{
if (!outer && VisibleSurfaces.Size() < unsigned(lm_background_updates))
if (!outer && VisibleTiles.Size() < unsigned(lm_background_updates))
{
for (auto& e : static_cast<DoomLevelSubmesh*>(level.levelMesh->StaticMesh.get())->Surfaces)
for (auto& e : level.levelMesh->StaticMesh->LightmapTiles)
{
if (e.NeedsUpdate && !e.IsSky && !e.PortalIndex)
if (e.NeedsUpdate)
{
VisibleSurfaces.Push(&e);
VisibleTiles.Push(&e);
if (VisibleSurfaces.Size() >= unsigned(lm_background_updates))
if (VisibleTiles.Size() >= unsigned(lm_background_updates))
break;
}
}
}
screen->UpdateLightmaps(VisibleSurfaces);
screen->UpdateLightmaps(VisibleTiles);
}
//-----------------------------------------------------------------------------

View file

@ -153,7 +153,7 @@ struct HWDrawInfo
TArray<HUDSprite> hudsprites; // These may just be stored by value.
TArray<AActor*> Coronas;
TArray<Fogball> Fogballs;
TArray<LevelMeshSurface*> VisibleSurfaces;
TArray<LightmapTile*> VisibleTiles;
uint64_t LastFrameTime = 0;
TArray<MissingTextureInfo> MissingUpperTextures;
@ -232,18 +232,22 @@ public:
return;
}
if (surface->LightmapTileIndex < 0)
return;
LightmapTile* tile = &surface->Submesh->LightmapTiles[surface->LightmapTileIndex];
if (lm_always_update || surface->AlwaysUpdate)
{
surface->NeedsUpdate = true;
tile->NeedsUpdate = true;
}
else if (VisibleSurfaces.Size() >= unsigned(lm_max_updates))
else if (VisibleTiles.Size() >= unsigned(lm_max_updates))
{
return;
}
if (surface->NeedsUpdate && !surface->PortalIndex && !surface->IsSky)
if (tile->NeedsUpdate)
{
VisibleSurfaces.Push(surface);
VisibleTiles.Push(tile);
}
}