Initial implementation of V2 lightmap lump loading

This commit is contained in:
RaveYard 2023-09-14 19:50:40 +02:00 committed by Christoph Oelckers
parent 3cdf28eb23
commit 00bd608dc5

View file

@ -86,6 +86,8 @@
#include "scene/hw_meshcache.h"
#include "version.h"
#include "vulkan/accelstructs/halffloat.h"
enum
{
MISSING_TEXTURE_WARN_LIMIT = 20
@ -3003,26 +3005,23 @@ void MapLoader::LoadLightmap(MapData* map)
Printf(PRINT_HIGH, "LoadLightmap: This is an old unsupported alpha version of the lightmap lump. Please rebuild the map with a newer version of zdray.\n");
return;
}
if (version != 1)
if (version == 1)
{
Printf(PRINT_HIGH, "LoadLightmap: This is an old unsupported version of the lightmap lump. Please rebuild the map with a newer version of zdray.\n");
return;
}
if (version != 2)
{
Printf(PRINT_HIGH, "LoadLightmap: unsupported lightmap lump version\n");
return;
}
uint16_t textureSize = fr.ReadUInt16();
uint16_t numTextures = fr.ReadUInt16();
uint32_t numSurfaces = fr.ReadUInt32();
uint32_t numTexPixels = fr.ReadUInt32();
uint32_t numTexCoords = fr.ReadUInt32();
uint32_t numSubsectors = fr.ReadUInt32();
uint32_t numTexBytes = numTextures * textureSize * textureSize * 3 * 2;
if (numSurfaces == 0 || numTexCoords == 0 || numTexBytes == 0)
return;
float sunDir[3], sunColor[3];
fr.Read(sunDir, sizeof(float) * 3);
fr.Read(sunColor, sizeof(float) * 3);
Level->SunDirection = FVector3(sunDir);
Level->SunColor = FVector3(sunColor);
if (numSurfaces == 0 || numTexCoords == 0 || numTexPixels == 0)
return;
bool errors = false;
@ -3041,7 +3040,21 @@ void MapLoader::LoadLightmap(MapData* map)
return 0xffffffff;
};
TArray<DoomLevelMeshSurface> zdraySurfaces;
auto getControlSector = [&](uint32_t index)
{
return index < Level->sectors.Size() ? &Level->sectors[index] : nullptr;
};
struct SurfaceEntry // V2 entries
{
uint32_t type, typeIndex;
uint32_t controlSector; // 0xFFFFFFFF is none
uint16_t width, height; // in pixels
uint32_t pixelsOffset; // offset in pixels array
uint32_t uvCount, uvOffset;
};
TArray<SurfaceEntry> zdraySurfaces;
for (auto& surface : Level->levelMesh->Surfaces)
{
@ -3050,13 +3063,17 @@ void MapLoader::LoadLightmap(MapData* map)
for (uint32_t i = 0; i < numSurfaces; i++)
{
LevelMeshSurfaceType type = (LevelMeshSurfaceType)fr.ReadUInt32();
uint32_t typeIndex = fr.ReadUInt32();
uint32_t controlSectorIndex = fr.ReadUInt32();
uint32_t lightmapNum = fr.ReadUInt32();
uint32_t firstTexCoord = fr.ReadUInt32();
SurfaceEntry surface;
surface.type = fr.ReadUInt32();
surface.typeIndex = fr.ReadUInt32();
surface.controlSector = fr.ReadUInt32();
surface.width = fr.ReadUInt16();
surface.height = fr.ReadUInt16();
surface.pixelsOffset = fr.ReadUInt32();
surface.uvCount = fr.ReadUInt32();
surface.uvOffset = fr.ReadUInt32();
auto controlSector = controlSectorIndex < Level->sectors.Size() ? &Level->sectors[controlSectorIndex] : nullptr;
auto controlSector = getControlSector(surface.controlSector);
// Check against the internal levelmesh
@ -3070,12 +3087,11 @@ void MapLoader::LoadLightmap(MapData* map)
continue;
}
auto levelSurface = &Level->levelMesh->Surfaces[i];
if (levelSurface->Type != type || levelSurface->typeIndex != typeIndex || levelSurface->ControlSector != controlSector)
if (levelSurface->Type != surface.type || levelSurface->typeIndex != surface.typeIndex || levelSurface->ControlSector != controlSector)
{
auto internalIndex = findSurfaceIndex(type, typeIndex, controlSector);
auto internalIndex = findSurfaceIndex(surface.type, surface.typeIndex, controlSector);
if (internalIndex < Level->levelMesh->Surfaces.Size())
{
@ -3086,25 +3102,22 @@ void MapLoader::LoadLightmap(MapData* map)
errors = true;
if (developer >= 1)
{
Printf(PRINT_HIGH, "Lightmap lump surface %d mismatch. Couldn't find surface type:%d, typeindex:%d, controlsector:%d\n", i, type, typeIndex, controlSectorIndex);
Printf(PRINT_HIGH, "Lightmap lump surface %d mismatch. Couldn't find surface type:%d, typeindex:%d, controlsector:%d\n", i, surface.type, surface.typeIndex, surface.controlSector);
}
// TODO detailed printout
continue;
}
}
DoomLevelMeshSurface surface;
surface.startUvIndex = firstTexCoord;
surface.typeIndex = typeIndex;
surface.ControlSector = controlSector;
surface.Type = type;
surface.numVerts = levelSurface->numVerts;
surface.atlasPageIndex = lightmapNum;
zdraySurfaces.Push(surface);
}
// Load pixels
TArray<uint16_t> textureData;
textureData.Resize(numTexPixels * 3);
uint8_t* data = (uint8_t*)&textureData[0];
fr.Read(data, numTexPixels * 3 * sizeof(uint16_t));
// Load texture coordinates
TArray<FVector2> zdrayUvs;
zdrayUvs.Resize(numTexCoords);
@ -3113,65 +3126,64 @@ void MapLoader::LoadLightmap(MapData* map)
// Load lightmap textures
Level->levelMesh->LMTextureData.Resize(Level->levelMesh->LMTextureCount * Level->levelMesh->LMTextureSize * Level->levelMesh->LMTextureSize * 3);
TArray<uint16_t> textureData;
textureData.Resize((numTexBytes + 1) / 2);
uint8_t* data = (uint8_t*)&textureData[0];
fr.Read(data, numTexBytes);
for (auto& pixel : Level->levelMesh->LMTextureData)
{
pixel = floatToHalf(0.0);
}
// Remap the ZDRay atlas into internal lightmapper
auto textureSize = Level->levelMesh->LMTextureSize;
// Map surface pixels into atlas
for (auto& surface : zdraySurfaces)
{
auto& realSurface = Level->levelMesh->Surfaces[findSurfaceIndex(surface.Type, surface.typeIndex, surface.ControlSector)];
// what are the pixel boundaries in the atlas?
BBox bbox;
for (int i = 0; i < surface.numVerts; ++i)
{
auto& uv = zdrayUvs[surface.startUvIndex + i];
bbox.AddPoint(FVector3(uv.X, uv.Y, 0));
}
auto& realSurface = Level->levelMesh->Surfaces[findSurfaceIndex(surface.type, surface.typeIndex, getControlSector(surface.controlSector))];
// calculate pixel positions
int srcMinX = (int)floorf(bbox.min.X * textureSize - 1.0f);
int srcMinY = (int)floorf(bbox.min.Y * textureSize - 1.0f);
int srcMaxX = (int)ceilf(bbox.max.X * textureSize + 1.0f);
int srcMaxY = (int)ceilf(bbox.max.Y * textureSize + 1.0f);
int srcPage = surface.atlasPageIndex;
int srcW = srcMaxX - srcMinX;
int srcH = srcMaxY - srcMinY;
uint32_t srcPixelOffset = surface.pixelsOffset;
int dstX = realSurface.atlasX;
int dstY = realSurface.atlasY;
int dstPage = realSurface.atlasPageIndex;
// Sanity checks
if (srcMinX < 0 || srcMinY < 0 || srcMaxX > textureSize || srcMaxY > textureSize ||
dstX < 0 || dstY < 0 || dstX + srcW > Level->levelMesh->LMTextureSize || dstY + srcH > Level->levelMesh->LMTextureSize ||
srcPage >= numTextures || dstPage >= Level->levelMesh->LMTextureCount)
if (dstX < 0 || dstY < 0 || dstX + surface.width > textureSize || dstY + surface.height > textureSize || dstPage >= Level->levelMesh->LMTextureCount)
{
errors = true;
if (developer >= 1)
{
Printf("Can't remap lightmap surface ((%d, %d), (%d, %d), %d) -> ((%d, %d), (%d, %d), %d)\n", srcMinX, srcMinY, srcMaxX, srcMaxY, srcPage, dstX, dstY, dstX + srcW, dstY + srcH, dstPage);
Printf("Can't map lightmap surface pixels[%u] -> ((x:%d, y:%d), (x2:%d, y2:%d), page:%d)\n", srcPixelOffset, dstX, dstY, dstX + surface.width, dstY + surface.height, dstPage);
}
realSurface.needsUpdate = true;
continue;
}
// copy pixels
uint16_t* src = &textureData[0];
uint16_t* dst = &Level->levelMesh->LMTextureData[0];
for (int y = srcMinY, y2 = dstY; y < srcMaxY; ++y, ++y2)
if (developer >= 4)
{
for (int x = srcMinX, x2 = dstX; x < srcMaxX; ++x, ++x2)
{
int index = (x + y * textureSize + srcPage * textureSize * textureSize) * 3;
int dstIndex = (x2 + y2 * textureSize + dstPage * textureSize * textureSize) * 3;
Printf("Mapping lightmap surface pixels[%u] (count: %u) -> ((x:%d, y:%d), (x2:%d, y2:%d), page:%d) area: %u\n",
srcPixelOffset, surface.width * surface.height * 3,
dstX, dstY,
dstX + realSurface.texWidth, dstY + realSurface.texHeight,
dstPage,
realSurface.Area() * 3);
}
dst[dstIndex] = src[index];
dst[dstIndex + 1] = src[index + 1];
dst[dstIndex + 2] = src[index + 2];
// copy pixels
uint16_t* src = &textureData[srcPixelOffset];
uint16_t* dst = &Level->levelMesh->LMTextureData[dstPage * textureSize * textureSize * 3];
uint32_t srcIndex = 0;
for (int y = 0; y < surface.height; ++y)
{
for (int x = 0; x < surface.width; ++x)
{
uint32_t dstIndex = (dstX + x + (dstY + y) * textureSize) * 3;
dst[dstIndex] = src[srcIndex];
dst[dstIndex + 1] = src[srcIndex + 1];
dst[dstIndex + 2] = src[srcIndex + 2];
srcIndex += 3;
}
}
}