ZDRay lump loading adjustments
This commit is contained in:
parent
ac90f1099a
commit
ee7771f71f
8 changed files with 283 additions and 247 deletions
|
|
@ -361,6 +361,12 @@ public:
|
|||
return v;
|
||||
}
|
||||
|
||||
float ReadFloat()
|
||||
{
|
||||
float v = 0.0f;
|
||||
Read(&v, 4);
|
||||
return v;
|
||||
}
|
||||
|
||||
friend class FileSystem;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include "hw_levelmesh.h"
|
||||
#include "halffloat.h"
|
||||
|
||||
LevelMesh::LevelMesh()
|
||||
{
|
||||
|
|
@ -187,3 +188,105 @@ void LevelSubmesh::BuildTileSurfaceLists()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelSubmesh::SetupTileTransforms()
|
||||
{
|
||||
for (auto& tile : LightmapTiles)
|
||||
{
|
||||
tile.SetupTileTransform(LMTextureSize);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelSubmesh::PackLightmapAtlas(int lightmapStartIndex)
|
||||
{
|
||||
std::vector<LightmapTile*> sortedTiles;
|
||||
sortedTiles.reserve(LightmapTiles.Size());
|
||||
|
||||
for (auto& tile : LightmapTiles)
|
||||
{
|
||||
sortedTiles.push_back(&tile);
|
||||
}
|
||||
|
||||
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 (LightmapTile* tile : sortedTiles)
|
||||
{
|
||||
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;
|
||||
|
||||
tile->AtlasLocation.X = x;
|
||||
tile->AtlasLocation.Y = y;
|
||||
tile->AtlasLocation.ArrayIndex = lightmapStartIndex + (int)result.pageIndex;
|
||||
}
|
||||
|
||||
LMTextureCount = (int)packer.getNumPages();
|
||||
|
||||
// Calculate final texture coordinates
|
||||
for (int i = 0, count = GetSurfaceCount(); i < count; i++)
|
||||
{
|
||||
auto surface = GetSurface(i);
|
||||
if (surface->LightmapTileIndex >= 0)
|
||||
{
|
||||
const LightmapTile& tile = LightmapTiles[surface->LightmapTileIndex];
|
||||
for (int i = 0; i < surface->MeshLocation.NumVerts; i++)
|
||||
{
|
||||
auto& vertex = Mesh.Vertices[surface->MeshLocation.StartVertIndex + i];
|
||||
FVector2 uv = tile.ToUV(vertex.fPos(), (float)LMTextureSize);
|
||||
vertex.lu = uv.X;
|
||||
vertex.lv = uv.Y;
|
||||
vertex.lindex = (float)tile.AtlasLocation.ArrayIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // Debug atlas tile locations:
|
||||
float colors[30] =
|
||||
{
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f,
|
||||
1.0f, 0.0f, 1.0f,
|
||||
0.5f, 0.0f, 0.0f,
|
||||
0.0f, 0.5f, 0.0f,
|
||||
0.5f, 0.5f, 0.0f,
|
||||
0.0f, 0.5f, 0.5f,
|
||||
0.5f, 0.0f, 0.5f
|
||||
};
|
||||
LMTextureData.Resize(LMTextureSize * LMTextureSize * LMTextureCount * 3);
|
||||
uint16_t* pixels = LMTextureData.Data();
|
||||
for (LightmapTile& tile : LightmapTiles)
|
||||
{
|
||||
tile.NeedsUpdate = false;
|
||||
|
||||
int index = tile.Binding.TypeIndex;
|
||||
float* color = colors + (index % 10) * 3;
|
||||
|
||||
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 + tile.AtlasLocation.ArrayIndex * LMTextureSize * LMTextureSize + yy * LMTextureSize * 3;
|
||||
for (int xx = x; xx < x + w; xx++)
|
||||
{
|
||||
float gray = (yy - y) / (float)h;
|
||||
line[xx * 3] = floatToHalf(color[0] * gray);
|
||||
line[xx * 3 + 1] = floatToHalf(color[1] * gray);
|
||||
line[xx * 3 + 2] = floatToHalf(color[2] * gray);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0, count = GetSurfaceCount(); i < count; i++)
|
||||
{
|
||||
auto surface = GetSurface(i);
|
||||
surface->AlwaysUpdate = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
#include "hw_surfaceuniforms.h"
|
||||
#include <memory>
|
||||
|
||||
#include <dp_rect_pack.h>
|
||||
typedef dp::rect_pack::RectPacker<int> RectPacker;
|
||||
|
||||
struct LevelMeshTileStats;
|
||||
|
||||
struct LevelSubmeshDrawRange
|
||||
|
|
@ -61,9 +64,8 @@ public:
|
|||
void UpdateCollision();
|
||||
void GatherTilePixelStats(LevelMeshTileStats& stats);
|
||||
void BuildTileSurfaceLists();
|
||||
|
||||
private:
|
||||
FVector2 ToUV(const FVector3& vert, const LightmapTile* tile);
|
||||
void SetupTileTransforms();
|
||||
void PackLightmapAtlas(int lightmapStartIndex);
|
||||
};
|
||||
|
||||
class LevelMesh
|
||||
|
|
|
|||
|
|
@ -69,4 +69,96 @@ struct LightmapTile
|
|||
float v = (AtlasLocation.Y + (localPos | Transform.ProjLocalToV)) / textureSize;
|
||||
return FVector2(u, v);
|
||||
}
|
||||
|
||||
enum PlaneAxis
|
||||
{
|
||||
AXIS_YZ = 0,
|
||||
AXIS_XZ,
|
||||
AXIS_XY
|
||||
};
|
||||
|
||||
static PlaneAxis BestAxis(const FVector4& p)
|
||||
{
|
||||
float na = fabs(float(p.X));
|
||||
float nb = fabs(float(p.Y));
|
||||
float nc = fabs(float(p.Z));
|
||||
|
||||
// figure out what axis the plane lies on
|
||||
if (na >= nb && na >= nc)
|
||||
{
|
||||
return AXIS_YZ;
|
||||
}
|
||||
else if (nb >= na && nb >= nc)
|
||||
{
|
||||
return AXIS_XZ;
|
||||
}
|
||||
|
||||
return AXIS_XY;
|
||||
}
|
||||
|
||||
void SetupTileTransform(int textureSize)
|
||||
{
|
||||
BBox bounds = Bounds;
|
||||
|
||||
// round off dimensions
|
||||
FVector3 roundedSize;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
bounds.min[i] = SampleDimension * (floor(bounds.min[i] / SampleDimension) - 1);
|
||||
bounds.max[i] = SampleDimension * (ceil(bounds.max[i] / SampleDimension) + 1);
|
||||
roundedSize[i] = (bounds.max[i] - bounds.min[i]) / SampleDimension;
|
||||
}
|
||||
|
||||
FVector3 tCoords[2] = { FVector3(0.0f, 0.0f, 0.0f), FVector3(0.0f, 0.0f, 0.0f) };
|
||||
|
||||
PlaneAxis axis = BestAxis(Plane);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
switch (axis)
|
||||
{
|
||||
default:
|
||||
case AXIS_YZ:
|
||||
width = (int)roundedSize.Y;
|
||||
height = (int)roundedSize.Z;
|
||||
tCoords[0].Y = 1.0f / SampleDimension;
|
||||
tCoords[1].Z = 1.0f / SampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XZ:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Z;
|
||||
tCoords[0].X = 1.0f / SampleDimension;
|
||||
tCoords[1].Z = 1.0f / SampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XY:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Y;
|
||||
tCoords[0].X = 1.0f / SampleDimension;
|
||||
tCoords[1].Y = 1.0f / SampleDimension;
|
||||
break;
|
||||
}
|
||||
|
||||
// clamp width
|
||||
if (width > textureSize - 2)
|
||||
{
|
||||
tCoords[0] *= ((float)(textureSize - 2) / (float)width);
|
||||
width = (textureSize - 2);
|
||||
}
|
||||
|
||||
// clamp height
|
||||
if (height > textureSize - 2)
|
||||
{
|
||||
tCoords[1] *= ((float)(textureSize - 2) / (float)height);
|
||||
height = (textureSize - 2);
|
||||
}
|
||||
|
||||
Transform.TranslateWorldToLocal = bounds.min;
|
||||
Transform.ProjLocalToU = tCoords[0];
|
||||
Transform.ProjLocalToV = tCoords[1];
|
||||
|
||||
AtlasLocation.Width = width;
|
||||
AtlasLocation.Height = height;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3012,7 +3012,14 @@ void MapLoader::InitLevelMesh(MapData* map)
|
|||
Level->levelMesh = new DoomLevelMesh(*Level);
|
||||
|
||||
// Lightmap binding/loading
|
||||
LoadLightmap(map);
|
||||
if (!LoadLightmap(map))
|
||||
{
|
||||
if (Level->lightmaps)
|
||||
{
|
||||
Level->levelMesh->StaticMesh->SetupTileTransforms();
|
||||
Level->levelMesh->StaticMesh->PackLightmapAtlas(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MapLoader::LoadLightmap(MapData* map)
|
||||
|
|
@ -3025,12 +3032,12 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
return false;
|
||||
|
||||
int version = fr.ReadInt32();
|
||||
if (version < 2)
|
||||
if (version < 3)
|
||||
{
|
||||
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 false;
|
||||
}
|
||||
else if (version != 2)
|
||||
else if (version != 3)
|
||||
{
|
||||
Printf(PRINT_HIGH, "LoadLightmap: unsupported lightmap lump version\n");
|
||||
return false;
|
||||
|
|
@ -3038,14 +3045,13 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
|
||||
uint32_t numTiles = fr.ReadUInt32();
|
||||
uint32_t numTexPixels = fr.ReadUInt32();
|
||||
uint32_t numTexCoords = fr.ReadUInt32(); // To do: remove from a future version of the format. We don't need this.
|
||||
|
||||
if (developer >= 5)
|
||||
{
|
||||
Printf("LoadLightmap: Tiles: %u, Pixels: %u, UVs: %u\n", numTiles, numTexPixels, numTexCoords);
|
||||
Printf("LoadLightmap: Tiles: %u, Pixels: %u\n", numTiles, numTexPixels);
|
||||
}
|
||||
|
||||
if (numTiles == 0 || numTexCoords == 0 || numTexPixels == 0)
|
||||
if (numTiles == 0 || numTexPixels == 0)
|
||||
return false;
|
||||
|
||||
int errors = 0;
|
||||
|
|
@ -3058,9 +3064,9 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
uint32_t controlSector; // 0xFFFFFFFF is none
|
||||
uint16_t width, height; // in pixels
|
||||
uint32_t pixelsOffset; // offset in pixels array
|
||||
uint32_t uvCount, uvOffset;
|
||||
|
||||
DoomLevelMeshSurface* targetSurface;
|
||||
FVector3 translateWorldToLocal;
|
||||
FVector3 projLocalToU;
|
||||
FVector3 projLocalToV;
|
||||
};
|
||||
|
||||
TArray<TileEntry> tileEntries;
|
||||
|
|
@ -3076,8 +3082,15 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
entry.width = fr.ReadUInt16();
|
||||
entry.height = fr.ReadUInt16();
|
||||
entry.pixelsOffset = fr.ReadUInt32();
|
||||
entry.uvCount = fr.ReadUInt32();
|
||||
entry.uvOffset = fr.ReadUInt32();
|
||||
entry.translateWorldToLocal.X = fr.ReadFloat();
|
||||
entry.translateWorldToLocal.Y = fr.ReadFloat();
|
||||
entry.translateWorldToLocal.Z = fr.ReadFloat();
|
||||
entry.projLocalToU.X = fr.ReadFloat();
|
||||
entry.projLocalToU.Y = fr.ReadFloat();
|
||||
entry.projLocalToU.Z = fr.ReadFloat();
|
||||
entry.projLocalToV.X = fr.ReadFloat();
|
||||
entry.projLocalToV.Y = fr.ReadFloat();
|
||||
entry.projLocalToV.Z = fr.ReadFloat();
|
||||
}
|
||||
|
||||
// Load pixels
|
||||
|
|
@ -3086,18 +3099,9 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
uint8_t* data = (uint8_t*)&textureData[0];
|
||||
fr.Read(data, numTexPixels * 3 * sizeof(uint16_t));
|
||||
|
||||
// Load texture coordinates
|
||||
// TArray<FVector2> zdrayUvs;
|
||||
// zdrayUvs.Resize(numTexCoords);
|
||||
// fr.Read(&zdrayUvs[0], numTexCoords * 2 * sizeof(float));
|
||||
|
||||
auto submesh = Level->levelMesh->StaticMesh.get();
|
||||
const auto textureSize = submesh->LMTextureSize;
|
||||
|
||||
// Start with empty lightmap textures
|
||||
submesh->LMTextureData.Resize(submesh->LMTextureCount * textureSize * textureSize * 3);
|
||||
memset(submesh->LMTextureData.Data(), 0, submesh->LMTextureData.Size() * sizeof(uint16_t));
|
||||
|
||||
// Create lookup for finding tiles
|
||||
std::map<LightmapTileBinding, LightmapTile*> levelTiles;
|
||||
for (LightmapTile& tile : submesh->LightmapTiles)
|
||||
|
|
@ -3105,7 +3109,8 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
levelTiles[tile.Binding] = &tile;
|
||||
}
|
||||
|
||||
// Bind tiles and copy their pixels to the texture
|
||||
// Bind tiles and use the lump's tile transform
|
||||
TArray<std::pair<const TileEntry*, LightmapTile*>> foundBindings;
|
||||
for (const TileEntry& entry : tileEntries)
|
||||
{
|
||||
LightmapTileBinding binding;
|
||||
|
|
@ -3122,34 +3127,58 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
continue;
|
||||
}
|
||||
|
||||
LightmapTile* tile = it->second;
|
||||
|
||||
// To do: add transform info to the lump so that we can stretch the pixels as the lump lightmapper might be using fixed point coordinates that could cause alignment issues
|
||||
|
||||
if (tile->AtlasLocation.Width != entry.width || tile->AtlasLocation.Height != entry.height)
|
||||
if (entry.width == 0 || entry.height == 0)
|
||||
{
|
||||
if (errors < 10 && developer >= 1)
|
||||
Printf("Lightmap tile size mismatch (type = %d, index = %d, control sector = %d)\n", entry.type, entry.typeIndex, entry.controlSector);
|
||||
Printf("Invalid lightmap tile found (type = %d, index = %d, control sector = %d)\n", entry.type, entry.typeIndex, entry.controlSector);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint16_t* src = textureData.Data() + entry.pixelsOffset;
|
||||
LightmapTile* tile = it->second;
|
||||
|
||||
tile->AtlasLocation.Width = entry.width;
|
||||
tile->AtlasLocation.Height = entry.height;
|
||||
tile->Transform.TranslateWorldToLocal = entry.translateWorldToLocal;
|
||||
tile->Transform.ProjLocalToU = entry.projLocalToU;
|
||||
tile->Transform.ProjLocalToV = entry.projLocalToV;
|
||||
tile->NeedsUpdate = false;
|
||||
|
||||
foundBindings.Push({ &entry, tile });
|
||||
}
|
||||
|
||||
// Setup the tile transform for any tile missing in the lump (shouldn't be any, but if there are we let the lightmapper bake them)
|
||||
for (auto& tile : submesh->LightmapTiles)
|
||||
{
|
||||
if (tile.NeedsUpdate)
|
||||
tile.SetupTileTransform(submesh->LMTextureSize);
|
||||
}
|
||||
|
||||
// Place all tiles in atlas textures
|
||||
submesh->PackLightmapAtlas(0);
|
||||
|
||||
// Start with empty lightmap textures
|
||||
submesh->LMTextureData.Resize(submesh->LMTextureCount * textureSize * textureSize * 3);
|
||||
memset(submesh->LMTextureData.Data(), 0, submesh->LMTextureData.Size() * sizeof(uint16_t));
|
||||
|
||||
// Copy tile pixels to the texture
|
||||
for (auto& binding : foundBindings)
|
||||
{
|
||||
const TileEntry* entry = binding.first;
|
||||
LightmapTile* tile = binding.second;
|
||||
|
||||
const uint16_t* src = textureData.Data() + entry->pixelsOffset;
|
||||
uint16_t* dst = &submesh->LMTextureData[tile->AtlasLocation.ArrayIndex * textureSize * textureSize * 3];
|
||||
int destx = tile->AtlasLocation.X;
|
||||
int desty = tile->AtlasLocation.Y;
|
||||
int width = tile->AtlasLocation.Width;
|
||||
int height = tile->AtlasLocation.Height;
|
||||
|
||||
int x = tile->AtlasLocation.X;
|
||||
int y = tile->AtlasLocation.Y;
|
||||
int w = tile->AtlasLocation.Width;
|
||||
int h = tile->AtlasLocation.Height;
|
||||
|
||||
for (int yy = 0; yy < w; yy++)
|
||||
for (int yy = 0; yy < height; yy++)
|
||||
{
|
||||
const uint16_t* srcline = src + yy * w * 3;
|
||||
uint16_t* dstline = dst + (x + yy * textureSize) * 3;
|
||||
for (int xx = 0, end = w * 3; xx < end; xx++)
|
||||
{
|
||||
dstline[xx] = srcline[xx];
|
||||
}
|
||||
uint16_t* dstline = dst + (destx + (desty + yy) * textureSize) * 3;
|
||||
const uint16_t* srcline = src + yy * (width * 3);
|
||||
memcpy(dstline, srcline, width * 6);
|
||||
}
|
||||
|
||||
tile->NeedsUpdate = false;
|
||||
|
|
|
|||
|
|
@ -154,7 +154,12 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap)
|
|||
|
||||
void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap)
|
||||
{
|
||||
static_cast<DoomLevelSubmesh*>(DynamicMesh.get())->Update(doomMap, static_cast<DoomLevelSubmesh*>(StaticMesh.get())->LMTextureCount);
|
||||
static_cast<DoomLevelSubmesh*>(DynamicMesh.get())->Update(doomMap);
|
||||
if (doomMap.lightmaps)
|
||||
{
|
||||
DynamicMesh->SetupTileTransforms();
|
||||
DynamicMesh->PackLightmapAtlas(StaticMesh->LMTextureCount);
|
||||
}
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::TraceSky(const FVector3& start, FVector3 direction, float dist)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "a_dynlight.h"
|
||||
#include "halffloat.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_vertexbuilder.h"
|
||||
#include "hwrenderer/scene/hw_drawstructs.h"
|
||||
|
|
@ -32,12 +31,10 @@ DoomLevelSubmesh::DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, b
|
|||
SortIndexes();
|
||||
BuildTileSurfaceLists();
|
||||
UpdateCollision();
|
||||
if (doomMap.lightmaps)
|
||||
PackLightmapAtlas(doomMap, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::Update(FLevelLocals& doomMap, int lightmapStartIndex)
|
||||
void DoomLevelSubmesh::Update(FLevelLocals& doomMap)
|
||||
{
|
||||
if (!StaticMesh)
|
||||
{
|
||||
|
|
@ -49,9 +46,6 @@ void DoomLevelSubmesh::Update(FLevelLocals& doomMap, int lightmapStartIndex)
|
|||
SortIndexes();
|
||||
BuildTileSurfaceLists();
|
||||
UpdateCollision();
|
||||
|
||||
if (doomMap.lightmaps)
|
||||
PackLightmapAtlas(doomMap, lightmapStartIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,11 +164,6 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
|
|||
state.SetRenderStyle(STYLE_Normal);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& tile : LightmapTiles)
|
||||
{
|
||||
SetupTileTransform(LMTextureSize, LMTextureSize, tile);
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWWall>& list, bool isSky, bool translucent)
|
||||
|
|
@ -620,98 +609,6 @@ void DoomLevelSubmesh::SetSideLightmap(DoomLevelMeshSurface* surface)
|
|||
}
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::PackLightmapAtlas(FLevelLocals& doomMap, int lightmapStartIndex)
|
||||
{
|
||||
std::vector<LightmapTile*> sortedTiles;
|
||||
sortedTiles.reserve(LightmapTiles.Size());
|
||||
|
||||
for (auto& tile : LightmapTiles)
|
||||
{
|
||||
sortedTiles.push_back(&tile);
|
||||
}
|
||||
|
||||
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 (LightmapTile* tile : sortedTiles)
|
||||
{
|
||||
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;
|
||||
|
||||
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++)
|
||||
{
|
||||
auto& vertex = Mesh.Vertices[surface.MeshLocation.StartVertIndex + i];
|
||||
FVector2 uv = tile.ToUV(vertex.fPos(), (float)LMTextureSize);
|
||||
vertex.lu = uv.X;
|
||||
vertex.lv = uv.Y;
|
||||
vertex.lindex = (float)tile.AtlasLocation.ArrayIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // Debug atlas tile locations:
|
||||
float colors[30] =
|
||||
{
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f,
|
||||
1.0f, 0.0f, 1.0f,
|
||||
0.5f, 0.0f, 0.0f,
|
||||
0.0f, 0.5f, 0.0f,
|
||||
0.5f, 0.5f, 0.0f,
|
||||
0.0f, 0.5f, 0.5f,
|
||||
0.5f, 0.0f, 0.5f
|
||||
};
|
||||
LMTextureData.Resize(LMTextureSize * LMTextureSize * LMTextureCount * 3);
|
||||
uint16_t* pixels = LMTextureData.Data();
|
||||
for (LightmapTile& tile : LightmapTiles)
|
||||
{
|
||||
tile.NeedsUpdate = false;
|
||||
|
||||
int index = tile.Binding.TypeIndex;
|
||||
float* color = colors + (index % 10) * 3;
|
||||
|
||||
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 + tile.AtlasLocation.ArrayIndex * LMTextureSize * LMTextureSize + yy * LMTextureSize * 3;
|
||||
for (int xx = x; xx < x + w; xx++)
|
||||
{
|
||||
float gray = (yy - y) / (float)h;
|
||||
line[xx * 3] = floatToHalf(color[0] * gray);
|
||||
line[xx * 3 + 1] = floatToHalf(color[1] * gray);
|
||||
line[xx * 3 + 2] = floatToHalf(color[2] * gray);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (DoomLevelMeshSurface& surf : Surfaces)
|
||||
{
|
||||
surf.AlwaysUpdate = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BBox DoomLevelSubmesh::GetBoundsFromSurface(const LevelMeshSurface& surface) const
|
||||
{
|
||||
BBox bounds;
|
||||
|
|
@ -728,88 +625,3 @@ BBox DoomLevelSubmesh::GetBoundsFromSurface(const LevelMeshSurface& surface) con
|
|||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
DoomLevelSubmesh::PlaneAxis DoomLevelSubmesh::BestAxis(const FVector4& p)
|
||||
{
|
||||
float na = fabs(float(p.X));
|
||||
float nb = fabs(float(p.Y));
|
||||
float nc = fabs(float(p.Z));
|
||||
|
||||
// figure out what axis the plane lies on
|
||||
if (na >= nb && na >= nc)
|
||||
{
|
||||
return AXIS_YZ;
|
||||
}
|
||||
else if (nb >= na && nb >= nc)
|
||||
{
|
||||
return AXIS_XZ;
|
||||
}
|
||||
|
||||
return AXIS_XY;
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LightmapTile& tile)
|
||||
{
|
||||
BBox bounds = tile.Bounds;
|
||||
|
||||
// round off dimensions
|
||||
FVector3 roundedSize;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
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(tile.Plane);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
switch (axis)
|
||||
{
|
||||
default:
|
||||
case AXIS_YZ:
|
||||
width = (int)roundedSize.Y;
|
||||
height = (int)roundedSize.Z;
|
||||
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 / 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 / tile.SampleDimension;
|
||||
tCoords[1].Y = 1.0f / tile.SampleDimension;
|
||||
break;
|
||||
}
|
||||
|
||||
// clamp width
|
||||
if (width > lightMapTextureWidth - 2)
|
||||
{
|
||||
tCoords[0] *= ((float)(lightMapTextureWidth - 2) / (float)width);
|
||||
width = (lightMapTextureWidth - 2);
|
||||
}
|
||||
|
||||
// clamp height
|
||||
if (height > lightMapTextureHeight - 2)
|
||||
{
|
||||
tCoords[1] *= ((float)(lightMapTextureHeight - 2) / (float)height);
|
||||
height = (lightMapTextureHeight - 2);
|
||||
}
|
||||
|
||||
tile.Transform.TranslateWorldToLocal = bounds.min;
|
||||
tile.Transform.ProjLocalToU = tCoords[0];
|
||||
tile.Transform.ProjLocalToV = tCoords[1];
|
||||
|
||||
tile.AtlasLocation.Width = width;
|
||||
tile.AtlasLocation.Height = height;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,9 @@
|
|||
#include "vectors.h"
|
||||
#include "r_defs.h"
|
||||
#include "bounds.h"
|
||||
#include <dp_rect_pack.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
typedef dp::rect_pack::RectPacker<int> RectPacker;
|
||||
|
||||
struct FLevelLocals;
|
||||
struct FPolyObj;
|
||||
struct HWWallDispatcher;
|
||||
|
|
@ -36,7 +33,7 @@ class DoomLevelSubmesh : public LevelSubmesh
|
|||
public:
|
||||
DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, bool staticMesh);
|
||||
|
||||
void Update(FLevelLocals& doomMap, int lightmapStartIndex);
|
||||
void Update(FLevelLocals& doomMap);
|
||||
|
||||
LevelMeshSurface* GetSurface(int index) override { return &Surfaces[index]; }
|
||||
unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const override { return (unsigned int)(ptrdiff_t)(static_cast<const DoomLevelMeshSurface*>(surface) - Surfaces.Data()); }
|
||||
|
|
@ -61,19 +58,9 @@ private:
|
|||
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWFlat>& list, bool isSky = false);
|
||||
|
||||
void LinkSurfaces(FLevelLocals& doomMap);
|
||||
void PackLightmapAtlas(FLevelLocals& doomMap, int lightmapStartIndex);
|
||||
|
||||
enum PlaneAxis
|
||||
{
|
||||
AXIS_YZ = 0,
|
||||
AXIS_XZ,
|
||||
AXIS_XY
|
||||
};
|
||||
|
||||
static PlaneAxis BestAxis(const FVector4& p);
|
||||
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
|
||||
|
||||
void SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LightmapTile& tile);
|
||||
int AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map<LightmapTileBinding, int>& bindings);
|
||||
int GetSampleDimension(const DoomLevelMeshSurface& surf);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue