Initialize lightmap texture in SetLevelMesh

Create VkLightmap class on VulkanRenderDevice
This commit is contained in:
Magnus Norddahl 2023-09-01 00:03:18 +02:00 committed by Christoph Oelckers
parent 6de6ae28e9
commit db5c659fab
15 changed files with 125 additions and 200 deletions

View file

@ -207,10 +207,14 @@ public:
std::unique_ptr<TriangleMeshShape> Collision; std::unique_ptr<TriangleMeshShape> Collision;
std::vector<std::unique_ptr<Surface>> surfaces; TArray<hwrenderer::Surface> Surfaces;
TArray<SmoothingGroup> smoothingGroups; // TODO fill TArray<SmoothingGroup> smoothingGroups; // TODO fill
TArray<Portal> portals; // TODO fill TArray<Portal> portals; // TODO fill
int LMTextureCount = 0;
int LMTextureSize = 0;
FVector3 SunDirection; FVector3 SunDirection;
FVector3 SunColor; FVector3 SunColor;

View file

@ -220,9 +220,6 @@ public:
virtual int GetClientHeight() = 0; virtual int GetClientHeight() = 0;
virtual void BlurScene(float amount) {} virtual void BlurScene(float amount) {}
virtual void GenerateLightmap(TArray<uint16_t>& LMTextureData, int LMTextureSize, hwrenderer::LevelMesh& mesh) {}
virtual void InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData) {}
// Interface to hardware rendering resources // Interface to hardware rendering resources
virtual IBuffer* CreateVertexBuffer(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute* attrs) { return nullptr; } virtual IBuffer* CreateVertexBuffer(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute* attrs) { return nullptr; }
virtual IBuffer* CreateIndexBuffer() { return nullptr; } virtual IBuffer* CreateIndexBuffer() { return nullptr; }

View file

@ -7,7 +7,6 @@
#include "filesystem.h" #include "filesystem.h"
#include "cmdlib.h" #include "cmdlib.h"
VkLightmap::VkLightmap(VulkanRenderDevice* fb) : fb(fb) VkLightmap::VkLightmap(VulkanRenderDevice* fb) : fb(fb)
{ {
useRayQuery = fb->GetDevice()->PhysicalDevice.Features.RayQuery.rayQuery; useRayQuery = fb->GetDevice()->PhysicalDevice.Features.RayQuery.rayQuery;
@ -95,9 +94,9 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex)
}; };
beginPass(); beginPass();
for (size_t i = 0; i < mesh->surfaces.size(); i++) for (unsigned int i = 0; i < mesh->Surfaces.Size(); i++)
{ {
hwrenderer::Surface* targetSurface = mesh->surfaces[i].get(); hwrenderer::Surface* targetSurface = &mesh->Surfaces[i];
if (targetSurface->atlasPageIndex != pageIndex) if (targetSurface->atlasPageIndex != pageIndex)
continue; continue;
@ -123,8 +122,6 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex)
int vertexCount = (int)surface->verts.Size(); int vertexCount = (int)surface->verts.Size();
if (lights.Pos + lightCount > lights.BufferSize || vertices.Pos + vertexCount > vertices.BufferSize) if (lights.Pos + lightCount > lights.BufferSize || vertices.Pos + vertexCount > vertices.BufferSize)
{ {
printf(".");
// Flush scene buffers // Flush scene buffers
FinishCommands(); FinishCommands();
lights.Pos = 0; lights.Pos = 0;
@ -134,8 +131,6 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex)
BeginCommands(); BeginCommands();
beginPass(); beginPass();
printf(".");
if (lights.Pos + lightCount > lights.BufferSize) if (lights.Pos + lightCount > lights.BufferSize)
{ {
throw std::runtime_error("SceneLightBuffer is too small!"); throw std::runtime_error("SceneLightBuffer is too small!");
@ -200,9 +195,9 @@ void VkLightmap::CreateAtlasImages()
const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles
RectPacker packer(atlasImageSize, atlasImageSize, RectPacker::Spacing(spacing)); RectPacker packer(atlasImageSize, atlasImageSize, RectPacker::Spacing(spacing));
for (size_t i = 0; i < mesh->surfaces.size(); i++) for (unsigned int i = 0; i < mesh->Surfaces.Size(); i++)
{ {
hwrenderer::Surface* surface = mesh->surfaces[i].get(); hwrenderer::Surface* surface = &mesh->Surfaces[i];
auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2); auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2);
surface->atlasX = result.pos.x + 1; surface->atlasX = result.pos.x + 1;
@ -309,9 +304,9 @@ void VkLightmap::DownloadAtlasImage(size_t pageIndex)
hvec4* pixels = (hvec4*)atlasImages[pageIndex].Transfer->Map(0, atlasImageSize * atlasImageSize * sizeof(hvec4)); hvec4* pixels = (hvec4*)atlasImages[pageIndex].Transfer->Map(0, atlasImageSize * atlasImageSize * sizeof(hvec4));
for (size_t i = 0; i < mesh->surfaces.size(); i++) for (unsigned int i = 0; i < mesh->Surfaces.Size(); i++)
{ {
hwrenderer::Surface* surface = mesh->surfaces[i].get(); hwrenderer::Surface* surface = &mesh->Surfaces[i];
if (surface->atlasPageIndex != pageIndex) if (surface->atlasPageIndex != pageIndex)
continue; continue;

View file

@ -144,7 +144,7 @@ void VkRaytrace::CreateVertexAndIndexBuffers()
surfaceBuffer = BufferBuilder() surfaceBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
.Size(Mesh->surfaces.size() * sizeof(SurfaceInfo)) .Size(Mesh->Surfaces.Size() * sizeof(SurfaceInfo))
.DebugName("surfaceBuffer") .DebugName("surfaceBuffer")
.Create(fb->GetDevice()); .Create(fb->GetDevice());

View file

@ -189,6 +189,35 @@ void VkTextureManager::CreateLightmap()
SetLightmap(1, 1, data); SetLightmap(1, 1, data);
} }
void VkTextureManager::CreateLightmap(int LMTextureSize, int LMTextureCount)
{
int w = LMTextureSize;
int h = LMTextureSize;
int count = LMTextureCount;
int pixelsize = 8;
Lightmap.Reset(fb);
Lightmap.Image = ImageBuilder()
.Size(w, h, 1, count)
.Format(VK_FORMAT_R16G16B16A16_SFLOAT)
.Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)
.DebugName("VkRenderBuffers.Lightmap")
.Create(fb->GetDevice());
Lightmap.View = ImageViewBuilder()
.Type(VK_IMAGE_VIEW_TYPE_2D_ARRAY)
.Image(Lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
.DebugName("VkRenderBuffers.LightmapView")
.Create(fb->GetDevice());
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
VkImageTransition()
.AddImage(&Lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, count)
.Execute(cmdbuffer);
}
void VkTextureManager::SetLightmap(int LMTextureSize, int LMTextureCount, const TArray<uint16_t>& LMTextureData) void VkTextureManager::SetLightmap(int LMTextureSize, int LMTextureCount, const TArray<uint16_t>& LMTextureData)
{ {
int w = LMTextureSize; int w = LMTextureSize;

View file

@ -23,6 +23,7 @@ public:
void BeginFrame(); void BeginFrame();
void CreateLightmap(int LMTextureSize, int LMTextureCount);
void SetLightmap(int LMTextureSize, int LMTextureCount, const TArray<uint16_t>& LMTextureData); void SetLightmap(int LMTextureSize, int LMTextureCount, const TArray<uint16_t>& LMTextureData);
VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex); VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex);

View file

@ -184,6 +184,7 @@ void VulkanRenderDevice::InitializeState()
mDescriptorSetManager.reset(new VkDescriptorSetManager(this)); mDescriptorSetManager.reset(new VkDescriptorSetManager(this));
mRenderPassManager.reset(new VkRenderPassManager(this)); mRenderPassManager.reset(new VkRenderPassManager(this));
mRaytrace.reset(new VkRaytrace(this)); mRaytrace.reset(new VkRaytrace(this));
mLightmap.reset(new VkLightmap(this));
mBufferManager->Init(); mBufferManager->Init();
@ -476,61 +477,6 @@ void VulkanRenderDevice::BeginFrame()
mDescriptorSetManager->BeginFrame(); mDescriptorSetManager->BeginFrame();
} }
void VulkanRenderDevice::GenerateLightmap(TArray<uint16_t>& LMTextureData, int LMTextureSize, hwrenderer::LevelMesh& mesh)
{
if (false && mesh.surfaces.size() > 0)
{
Printf("Running VkLightmap.\n");
//VkLightmap lightmap(this);
//lightmap.Raytrace(&mesh);
Printf("Copying data.\n");
// TODO refactor
auto clamp = [](float a, float min, float max) -> float { return a < min ? min : a > max ? max : a; };
std::sort(mesh.surfaces.begin(), mesh.surfaces.end(), [](const std::unique_ptr<hwrenderer::Surface>& a, const std::unique_ptr<hwrenderer::Surface>& b) { return a->texHeight != b->texHeight ? a->texHeight > b->texHeight : a->texWidth > b->texWidth; });
RectPacker packer(LMTextureSize, LMTextureSize, RectPacker::Spacing(0));
for (auto& surface : mesh.surfaces)
{
mesh.FinishSurface(LMTextureSize, LMTextureSize, packer, *surface.get());
uint16_t* currentTexture = LMTextureData.Data() + (LMTextureSize * LMTextureSize * 3) * surface->atlasPageIndex;
FVector3* colorSamples = surface->texPixels.data();
// store results to lightmap texture
for (int i = 0; i < surface->texHeight; i++)
{
for (int j = 0; j < surface->texWidth; j++)
{
// get texture offset
int offs = ((surface->texWidth * (i + surface->atlasY)) + surface->atlasX) * 3;
// convert RGB to bytes
currentTexture[offs + j * 3 + 0] = floatToHalf(clamp(colorSamples[i * surface->texWidth + j].X, 0.0f, 65000.0f));
currentTexture[offs + j * 3 + 1] = floatToHalf(clamp(colorSamples[i * surface->texWidth + j].Y, 0.0f, 65000.0f));
currentTexture[offs + j * 3 + 2] = floatToHalf(clamp(colorSamples[i * surface->texWidth + j].Z, 0.0f, 65000.0f));
}
}
}
}
}
void VulkanRenderDevice::InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData)
{
if (LMTextureData.Size() > 0)
{
GetTextureManager()->SetLightmap(LMTextureSize, LMTextureCount, LMTextureData);
LMTextureData.Reset(); // We no longer need this, release the memory
}
}
void VulkanRenderDevice::Draw2D() void VulkanRenderDevice::Draw2D()
{ {
::Draw2D(twod, *RenderState(0)); ::Draw2D(twod, *RenderState(0));
@ -589,6 +535,61 @@ void VulkanRenderDevice::PrintStartupLog()
void VulkanRenderDevice::SetLevelMesh(hwrenderer::LevelMesh* mesh) void VulkanRenderDevice::SetLevelMesh(hwrenderer::LevelMesh* mesh)
{ {
mRaytrace->SetLevelMesh(mesh); mRaytrace->SetLevelMesh(mesh);
if (mesh->Surfaces.Size() > 0)
{
#if 0 // To do: GetLightmap()->Raytrace should output directly to the lightmap texture instead of forcing us to download it to the CPU first
GetTextureManager()->CreateLightmap(mesh->LMTextureSize, mesh->LMTextureCount);
GetCommands()->WaitForCommands(false);
GetLightmap()->Raytrace(mesh);
#else // Temporary version using the old zdray Raytracer code as-is
Printf("Running VkLightmap.\n");
GetLightmap()->Raytrace(mesh);
Printf("Copying data.\n");
// TODO refactor
auto clamp = [](float a, float min, float max) -> float { return a < min ? min : a > max ? max : a; };
// BUG: This is a destructive action as it reorders the surfaces array that is indexed by MeshSurfaces
std::sort(mesh->Surfaces.begin(), mesh->Surfaces.end(), [](const hwrenderer::Surface& a, const hwrenderer::Surface& b) { return a.texHeight != b.texHeight ? a.texHeight > b.texHeight : a.texWidth > b.texWidth; });
RectPacker packer(mesh->LMTextureSize, mesh->LMTextureSize, RectPacker::Spacing(0));
TArray<uint16_t> LMTextureData;
LMTextureData.Resize(mesh->LMTextureSize * mesh->LMTextureSize * mesh->LMTextureCount * 3);
for (auto& surface : mesh->Surfaces)
{
mesh->FinishSurface(mesh->LMTextureSize, mesh->LMTextureSize, packer, surface);
uint16_t* currentTexture = LMTextureData.Data() + (mesh->LMTextureSize * mesh->LMTextureSize * 3) * surface.atlasPageIndex;
FVector3* colorSamples = surface.texPixels.data();
// store results to lightmap texture
for (int i = 0; i < surface.texHeight; i++)
{
for (int j = 0; j < surface.texWidth; j++)
{
// get texture offset
int offs = ((surface.texWidth * (i + surface.atlasY)) + surface.atlasX) * 3;
// convert RGB to bytes
currentTexture[offs + j * 3 + 0] = floatToHalf(clamp(colorSamples[i * surface.texWidth + j].X, 0.0f, 65000.0f));
currentTexture[offs + j * 3 + 1] = floatToHalf(clamp(colorSamples[i * surface.texWidth + j].Y, 0.0f, 65000.0f));
currentTexture[offs + j * 3 + 2] = floatToHalf(clamp(colorSamples[i * surface.texWidth + j].Z, 0.0f, 65000.0f));
}
}
}
GetTextureManager()->SetLightmap(mesh->LMTextureSize, mesh->LMTextureCount, LMTextureData);
#endif
}
} }
void VulkanRenderDevice::SetShadowMaps(const TArray<float>& lights, hwrenderer::LevelAABBTree* tree, bool newTree) void VulkanRenderDevice::SetShadowMaps(const TArray<float>& lights, hwrenderer::LevelAABBTree* tree, bool newTree)

View file

@ -15,6 +15,7 @@ class VkDescriptorSetManager;
class VkRenderPassManager; class VkRenderPassManager;
class VkFramebufferManager; class VkFramebufferManager;
class VkRaytrace; class VkRaytrace;
class VkLightmap;
class VkRenderState; class VkRenderState;
class VkStreamBuffer; class VkStreamBuffer;
class VkHardwareDataBuffer; class VkHardwareDataBuffer;
@ -38,6 +39,7 @@ public:
VkDescriptorSetManager* GetDescriptorSetManager() { return mDescriptorSetManager.get(); } VkDescriptorSetManager* GetDescriptorSetManager() { return mDescriptorSetManager.get(); }
VkRenderPassManager *GetRenderPassManager() { return mRenderPassManager.get(); } VkRenderPassManager *GetRenderPassManager() { return mRenderPassManager.get(); }
VkRaytrace* GetRaytrace() { return mRaytrace.get(); } VkRaytrace* GetRaytrace() { return mRaytrace.get(); }
VkLightmap* GetLightmap() { return mLightmap.get(); }
VkRenderState *GetRenderState(int threadIndex) { return mRenderState[threadIndex].get(); } VkRenderState *GetRenderState(int threadIndex) { return mRenderState[threadIndex].get(); }
VkPostprocess *GetPostprocess() { return mPostprocess.get(); } VkPostprocess *GetPostprocess() { return mPostprocess.get(); }
VkRenderBuffers *GetBuffers() { return mActiveRenderBuffers; } VkRenderBuffers *GetBuffers() { return mActiveRenderBuffers; }
@ -56,8 +58,6 @@ public:
void SetTextureFilterMode() override; void SetTextureFilterMode() override;
void StartPrecaching() override; void StartPrecaching() override;
void BeginFrame() override; void BeginFrame() override;
void GenerateLightmap(TArray<uint16_t>& LMTextureData, int LMTextureSize, hwrenderer::LevelMesh& mesh) override;
void InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData) override;
void BlurScene(float amount) override; void BlurScene(float amount) override;
void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D) override; void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D) override;
void AmbientOccludeScene(float m5) override; void AmbientOccludeScene(float m5) override;
@ -108,6 +108,7 @@ private:
std::unique_ptr<VkDescriptorSetManager> mDescriptorSetManager; std::unique_ptr<VkDescriptorSetManager> mDescriptorSetManager;
std::unique_ptr<VkRenderPassManager> mRenderPassManager; std::unique_ptr<VkRenderPassManager> mRenderPassManager;
std::unique_ptr<VkRaytrace> mRaytrace; std::unique_ptr<VkRaytrace> mRaytrace;
std::unique_ptr<VkLightmap> mLightmap;
std::vector<std::unique_ptr<VkRenderState>> mRenderState; std::vector<std::unique_ptr<VkRenderState>> mRenderState;
VkRenderBuffers *mActiveRenderBuffers = nullptr; VkRenderBuffers *mActiveRenderBuffers = nullptr;

View file

@ -396,9 +396,9 @@ void D_Render(std::function<void()> action, bool interpolate)
for (auto Level : AllLevels()) for (auto Level : AllLevels())
{ {
// Check for the presence of dynamic lights at the start of the frame once. // Check for the presence of dynamic lights at the start of the frame once.
if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4) || Level->LMTextureCount > 0) if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4) || Level->lightmaps)
{ {
Level->HasDynamicLights = Level->lights || Level->LMTextureCount > 0; Level->HasDynamicLights = Level->lights || Level->lightmaps;
} }
else Level->HasDynamicLights = false; // lights are off so effectively we have none. else Level->HasDynamicLights = false; // lights are off so effectively we have none.
if (interpolate) Level->interpolator.DoInterpolations(I_GetTimeFrac()); if (interpolate) Level->interpolator.DoInterpolations(I_GetTimeFrac());

View file

@ -454,11 +454,8 @@ public:
TArray<FLinePortal> linePortals; TArray<FLinePortal> linePortals;
// Lightmaps // Lightmaps
bool lightmaps = false;
TArray<LightmapSurface> LMSurfaces; TArray<LightmapSurface> LMSurfaces;
TArray<float> LMTexCoords;
int LMTextureCount = 0;
int LMTextureSize = 0;
TArray<uint16_t> LMTextureData;
FVector3 SunDirection; FVector3 SunDirection;
FVector3 SunColor; FVector3 SunColor;

View file

@ -3214,10 +3214,6 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
Level->levelMesh = new DoomLevelMesh(*Level); Level->levelMesh = new DoomLevelMesh(*Level);
InitLightmap(map); InitLightmap(map);
screen->GenerateLightmap(Level->LMTextureData, Level->LMTextureSize, *Level->levelMesh);
screen->InitLightmap(Level->LMTextureSize, Level->LMTextureCount, Level->LMTextureData);
for (int i = 0; i < MAXPLAYERS; ++i) for (int i = 0; i < MAXPLAYERS; ++i)
{ {
if (Level->PlayerInGame(i) && Level->Players[i]->mo != nullptr) if (Level->PlayerInGame(i) && Level->Players[i]->mo != nullptr)
@ -3330,96 +3326,6 @@ void MapLoader::SetSideLightmap(const LightmapSurface &surface)
} }
} }
#include "vulkan/accelstructs/halffloat.h"
void MapLoader::GenerateLightmap(const DoomLevelMesh& mesh, int atlasPages, int atlasWidth, int atlasHeight)
{
Level->LMTextureData.Resize(atlasWidth * atlasHeight * 3 * atlasPages);
uint16_t* ptr = Level->LMTextureData.Data();
for (int i = 0; i < atlasPages; ++i)
{
for (int y = 0; y < atlasWidth; ++y)
{
for (int x = 0; x < atlasHeight; ++x)
{
/**(ptr++) = floatToHalf(float(x) / width);
*(ptr++) = floatToHalf(float(y) / height);
*(ptr++) = floatToHalf((x + y) % 2 == 0 ? 1.0f : 0.0f);*/
switch (i % 3)
{
case 0:
*(ptr++) = floatToHalf(1.0f);
*(ptr++) = floatToHalf(0.0f);
*(ptr++) = floatToHalf(0.0f);
break;
case 1:
*(ptr++) = floatToHalf(0.0f);
*(ptr++) = floatToHalf(1.0f);
*(ptr++) = floatToHalf(0.0f);
break;
case 2:
*(ptr++) = floatToHalf(0.0f);
*(ptr++) = floatToHalf(0.0f);
*(ptr++) = floatToHalf(1.0f);
break;
}
}
}
}
auto get_xy = [&](int page, int x, int y) -> uint16_t*
{
return Level->LMTextureData.Data() + ((y * atlasWidth) + x + (atlasHeight * atlasWidth * page)) * 3;
};
//#if 0
srand(1337);
for (auto& surface : mesh.Surfaces)
{
float r;
float g;
float b;
r = rand() % 32 / 32.0f;
g = rand() % 32 / 32.0f;
b = rand() % 32 / 32.0f;
for (int y = 0; y <= surface.texHeight; ++y)
{
for (int x = 0; x <= surface.texWidth; ++x)
{
auto ptr = get_xy(surface.atlasPageIndex, surface.atlasX + x, surface.atlasY + y);
ptr[0] = floatToHalf(r);
ptr[1] = floatToHalf(g);
ptr[2] = floatToHalf(b);
if (x % 4 == 0 || y % 4 == 0)
{
ptr[0] = floatToHalf(0.0f);
ptr[1] = floatToHalf(0.0f);
ptr[2] = floatToHalf(0.0f);
}
/*if (Level->levelMesh->TraceSky(surface.worldOrigin - surface.worldStepX * 0.5f - surface.worldStepY * 0.5f + surface.worldStepX * x + surface.worldStepY * y + FVector3(surface.plane.Normal()), Level->SunDirection, 32000.0f))
{
ptr[0] = floatToHalf(Level->SunColor.X);
ptr[1] = floatToHalf(Level->SunColor.Y);
ptr[2] = floatToHalf(Level->SunColor.Z);
}
else
{
ptr[0] = 0;
ptr[1] = 0;
ptr[2] = 0;
}*/
}
}
}
}
void MapLoader::BindLightmapSurfacesToGeometry() void MapLoader::BindLightmapSurfacesToGeometry()
{ {
// Allocate room for all surfaces // Allocate room for all surfaces
@ -3487,11 +3393,7 @@ void MapLoader::BindLightmapSurfacesToGeometry()
void MapLoader::InitLightmap(MapData* map) void MapLoader::InitLightmap(MapData* map)
{ {
// We have to reset everything as FLevelLocals is recycled between maps // We have to reset everything as FLevelLocals is recycled between maps
Level->LMTexCoords.Reset();
Level->LMSurfaces.Reset(); Level->LMSurfaces.Reset();
Level->LMTextureData.Reset();
Level->LMTextureSize = 1024; // TODO cvar
// TODO read from ZDRayInfoThing // TODO read from ZDRayInfoThing
Level->SunColor = FVector3(1.f, 1.f, 1.f); Level->SunColor = FVector3(1.f, 1.f, 1.f);
@ -3500,9 +3402,8 @@ void MapLoader::InitLightmap(MapData* map)
Level->levelMesh->SunColor = Level->SunColor; // TODO keep only one copy? Level->levelMesh->SunColor = Level->SunColor; // TODO keep only one copy?
Level->levelMesh->SunDirection = Level->SunDirection; Level->levelMesh->SunDirection = Level->SunDirection;
Level->LMTextureCount = Level->levelMesh->SetupLightmapUvs(Level->LMTextureSize); Level->lightmaps = true;
GenerateLightmap(*Level->levelMesh, Level->LMTextureCount, Level->LMTextureSize, Level->LMTextureSize);
BindLightmapSurfacesToGeometry(); BindLightmapSurfacesToGeometry();
} }

View file

@ -312,7 +312,6 @@ public:
void LoadLightmap(MapData *map); void LoadLightmap(MapData *map);
#endif #endif
void InitLightmap(MapData* map); void InitLightmap(MapData* map);
void GenerateLightmap(const DoomLevelMesh& mesh, int atlasPages, int atlasWidth, int atlasHeight);
void BindLightmapSurfacesToGeometry(); void BindLightmapSurfacesToGeometry();

View file

@ -337,7 +337,7 @@ void DoomLevelMesh::CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub,
surf.type = hwrenderer::ST_FLOOR; surf.type = hwrenderer::ST_FLOOR;
surf.typeIndex = typeIndex; surf.typeIndex = typeIndex;
surf.controlSector = is3DFloor ? sector : nullptr; surf.controlSector = is3DFloor ? sector : nullptr;
surf.plane = FVector4(plane.Normal().X, plane.Normal().Y, plane.Normal().Z, plane.D); surf.plane = FVector4((float)plane.Normal().X, (float)plane.Normal().Y, (float)plane.Normal().Z, (float)plane.D);
Surfaces.Push(surf); Surfaces.Push(surf);
} }
@ -376,7 +376,7 @@ void DoomLevelMesh::CreateCeilingSurface(FLevelLocals &doomMap, subsector_t *sub
surf.type = hwrenderer::ST_CEILING; surf.type = hwrenderer::ST_CEILING;
surf.typeIndex = typeIndex; surf.typeIndex = typeIndex;
surf.controlSector = is3DFloor ? sector : nullptr; surf.controlSector = is3DFloor ? sector : nullptr;
surf.plane = FVector4(plane.Normal().X, plane.Normal().Y, plane.Normal().Z, plane.D); surf.plane = FVector4((float)plane.Normal().X, (float)plane.Normal().Y, (float)plane.Normal().Z, (float)plane.D);
Surfaces.Push(surf); Surfaces.Push(surf);
} }
@ -487,21 +487,23 @@ void DoomLevelMesh::DumpMesh(const FString& filename) const
fclose(f); fclose(f);
} }
int DoomLevelMesh::SetupLightmapUvs(int lightmapSize) void DoomLevelMesh::SetupLightmapUvs()
{ {
LMTextureSize = 1024; // TODO cvar
std::vector<Surface*> sortedSurfaces; std::vector<Surface*> sortedSurfaces;
sortedSurfaces.reserve(Surfaces.Size()); sortedSurfaces.reserve(Surfaces.Size());
for (auto& surface : Surfaces) for (auto& surface : Surfaces)
{ {
BuildSurfaceParams(lightmapSize, lightmapSize, surface); BuildSurfaceParams(LMTextureSize, LMTextureSize, surface);
sortedSurfaces.push_back(&surface); sortedSurfaces.push_back(&surface);
} }
#if 0
for (const auto& surface : Surfaces) for (const auto& surface : Surfaces)
{ {
auto hwSurface = std::make_unique<hwrenderer::Surface>(); hwrenderer::Surface hwSurface;
for (int i = 0; i < surface.numVerts; ++i) for (int i = 0; i < surface.numVerts; ++i)
{ {
@ -535,36 +537,37 @@ int DoomLevelMesh::SetupLightmapUvs(int lightmapSize)
} }
// TODO push // TODO push
surfaces.push_back(std::move(hwSurface)); Surfaces.push_back(hwSurface);
SurfaceInfo info; SurfaceInfo info;
info.Normal = surface.plane.XYZ(); info.Normal = surface.plane.XYZ();
info.PortalIndex = 0; info.PortalIndex = 0;
info.SamplingDistance = surface.sampleDimension; info.SamplingDistance = (float)surface.sampleDimension;
info.Sky = surface.bSky; info.Sky = surface.bSky;
surfaceInfo.Push(info); surfaceInfo.Push(info);
} }
#endif
{ {
hwrenderer::SmoothingGroup smoothing; hwrenderer::SmoothingGroup smoothing;
for (auto& surface : surfaces) for (auto& surface : Surfaces)
{ {
smoothing.surfaces.push_back(surface.get()); smoothing.surfaces.push_back(&surface);
} }
smoothingGroups.Push(std::move(smoothing)); smoothingGroups.Push(std::move(smoothing));
} }
std::sort(sortedSurfaces.begin(), sortedSurfaces.end(), [](Surface* a, Surface* b) { return a->texHeight != b->texHeight ? a->texHeight > b->texHeight : a->texWidth > b->texWidth; }); std::sort(sortedSurfaces.begin(), sortedSurfaces.end(), [](Surface* a, Surface* b) { return a->texHeight != b->texHeight ? a->texHeight > b->texHeight : a->texWidth > b->texWidth; });
RectPacker packer(lightmapSize, lightmapSize, RectPacker::Spacing(0)); RectPacker packer(LMTextureSize, LMTextureSize, RectPacker::Spacing(0));
for (Surface* surf : sortedSurfaces) for (Surface* surf : sortedSurfaces)
{ {
FinishSurface(lightmapSize, lightmapSize, packer, *surf); FinishSurface(LMTextureSize, LMTextureSize, packer, *surf);
} }
// You have no idea how long this took me to figure out... // You have no idea how long this took me to figure out...
@ -589,8 +592,7 @@ int DoomLevelMesh::SetupLightmapUvs(int lightmapSize)
} }
} }
LMTextureCount = (int)packer.getNumPages();
return packer.getNumPages();
} }
void DoomLevelMesh::FinishSurface(int lightmapTextureWidth, int lightmapTextureHeight, RectPacker& packer, Surface& surface) void DoomLevelMesh::FinishSurface(int lightmapTextureWidth, int lightmapTextureHeight, RectPacker& packer, Surface& surface)
@ -642,7 +644,7 @@ void DoomLevelMesh::FinishSurface(int lightmapTextureWidth, int lightmapTextureH
BBox DoomLevelMesh::GetBoundsFromSurface(const Surface& surface) const BBox DoomLevelMesh::GetBoundsFromSurface(const Surface& surface) const
{ {
constexpr float M_INFINITY = 1e30; // TODO cleanup constexpr float M_INFINITY = 1e30f; // TODO cleanup
FVector3 low(M_INFINITY, M_INFINITY, M_INFINITY); FVector3 low(M_INFINITY, M_INFINITY, M_INFINITY);
FVector3 hi(-M_INFINITY, -M_INFINITY, -M_INFINITY); FVector3 hi(-M_INFINITY, -M_INFINITY, -M_INFINITY);

View file

@ -25,18 +25,16 @@ public:
return true; return true;
int surfaceIndex = MeshSurfaces[hit.triangle]; int surfaceIndex = MeshSurfaces[hit.triangle];
const hwrenderer::Surface& surface = Surfaces[surfaceIndex]; return Surfaces[surfaceIndex].bSky;
return surface.bSky;
} }
TArray<hwrenderer::Surface> Surfaces;
TArray<FVector2> LightmapUvs; TArray<FVector2> LightmapUvs;
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2); static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
void DumpMesh(const FString& filename) const; void DumpMesh(const FString& filename) const;
int SetupLightmapUvs(int lightmapSize); void SetupLightmapUvs();
private: private:
void CreateSubsectorSurfaces(FLevelLocals &doomMap); void CreateSubsectorSurfaces(FLevelLocals &doomMap);

View file

@ -83,7 +83,7 @@ public:
bool TraceSunVisibility(float x, float y, float z) bool TraceSunVisibility(float x, float y, float z)
{ {
if (level.LMTextureCount == 0 || !Actor) if (!level.lightmaps || !Actor)
return false; return false;
if (!ActorMoved && CurrentBit < 64) if (!ActorMoved && CurrentBit < 64)