Add support for multiple meshes (DoomLevelSubmesh)
This commit is contained in:
parent
fae22f1bb7
commit
65929d021f
8 changed files with 292 additions and 347 deletions
|
|
@ -183,17 +183,44 @@ struct LevelMeshSurfaceStats
|
|||
Stats surfaces, pixels;
|
||||
};
|
||||
|
||||
class LevelMesh
|
||||
class LevelSubmesh
|
||||
{
|
||||
public:
|
||||
LevelMesh()
|
||||
LevelSubmesh()
|
||||
{
|
||||
// Default portal
|
||||
LevelMeshPortal portal;
|
||||
Portals.Push(portal);
|
||||
|
||||
// Default empty mesh (we can't make it completely empty since vulkan doesn't like that)
|
||||
float minval = -100001.0f;
|
||||
float maxval = -100000.0f;
|
||||
MeshVertices.Push({ minval, minval, minval });
|
||||
MeshVertices.Push({ maxval, minval, minval });
|
||||
MeshVertices.Push({ maxval, maxval, minval });
|
||||
MeshVertices.Push({ minval, minval, minval });
|
||||
MeshVertices.Push({ minval, maxval, minval });
|
||||
MeshVertices.Push({ maxval, maxval, minval });
|
||||
MeshVertices.Push({ minval, minval, maxval });
|
||||
MeshVertices.Push({ maxval, minval, maxval });
|
||||
MeshVertices.Push({ maxval, maxval, maxval });
|
||||
MeshVertices.Push({ minval, minval, maxval });
|
||||
MeshVertices.Push({ minval, maxval, maxval });
|
||||
MeshVertices.Push({ maxval, maxval, maxval });
|
||||
|
||||
MeshVertexUVs.Resize(MeshVertices.Size());
|
||||
|
||||
for (int i = 0; i < 3 * 4; i++)
|
||||
MeshElements.Push(i);
|
||||
|
||||
UpdateCollision();
|
||||
}
|
||||
|
||||
virtual ~LevelMesh() = default;
|
||||
virtual ~LevelSubmesh() = default;
|
||||
|
||||
virtual LevelMeshSurface* GetSurface(int index) { return nullptr; }
|
||||
virtual unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const { return 0xffffffff; }
|
||||
virtual int GetSurfaceCount() { return 0; }
|
||||
|
||||
TArray<FVector3> MeshVertices;
|
||||
TArray<FVector2> MeshVertexUVs;
|
||||
|
|
@ -201,26 +228,26 @@ public:
|
|||
TArray<uint32_t> MeshElements;
|
||||
TArray<int> MeshSurfaceIndexes;
|
||||
|
||||
std::unique_ptr<TriangleMeshShape> Collision;
|
||||
|
||||
virtual LevelMeshSurface* GetSurface(int index) { return nullptr; }
|
||||
virtual unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const { return 0xffffffff; }
|
||||
virtual int GetSurfaceCount() { return 0; }
|
||||
|
||||
virtual int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { return 0; }
|
||||
|
||||
TArray<LevelMeshPortal> Portals;
|
||||
|
||||
std::unique_ptr<TriangleMeshShape> Collision;
|
||||
|
||||
// Lightmap atlas
|
||||
int LMTextureCount = 0;
|
||||
int LMTextureSize = 0;
|
||||
TArray<uint16_t> LMTextureData; // TODO better place for this?
|
||||
TArray<uint16_t> LMTextureData;
|
||||
|
||||
inline uint32_t AtlasPixelCount() const { return uint32_t(LMTextureCount * LMTextureSize * LMTextureSize); }
|
||||
inline LevelMeshSurfaceStats GatherSurfacePixelStats() //const
|
||||
uint16_t LightmapSampleDistance = 16;
|
||||
|
||||
uint32_t AtlasPixelCount() const { return uint32_t(LMTextureCount * LMTextureSize * LMTextureSize); }
|
||||
|
||||
void UpdateCollision()
|
||||
{
|
||||
LevelMeshSurfaceStats stats;
|
||||
Collision = std::make_unique<TriangleMeshShape>(MeshVertices.Data(), MeshVertices.Size(), MeshElements.Data(), MeshElements.Size());
|
||||
}
|
||||
|
||||
void GatherSurfacePixelStats(LevelMeshSurfaceStats& stats)
|
||||
{
|
||||
int count = GetSurfaceCount();
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
|
|
@ -240,63 +267,9 @@ public:
|
|||
stats.pixels.sky += area;
|
||||
}
|
||||
}
|
||||
|
||||
stats.surfaces.total = count;
|
||||
return stats;
|
||||
stats.surfaces.total += count;
|
||||
}
|
||||
|
||||
// Map defaults
|
||||
FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f);
|
||||
FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f);
|
||||
uint16_t LightmapSampleDistance = 16;
|
||||
|
||||
LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist)
|
||||
{
|
||||
maxDist = std::max(maxDist - 10.0f, 0.0f);
|
||||
|
||||
FVector3 origin = start;
|
||||
FVector3 end;
|
||||
|
||||
auto collision = Collision.get();
|
||||
|
||||
LevelMeshSurface* hitSurface = nullptr;
|
||||
|
||||
while (true)
|
||||
{
|
||||
end = origin + direction * maxDist;
|
||||
|
||||
auto hit = TriangleMeshShape::find_first_hit(collision, origin, end);
|
||||
|
||||
if (hit.triangle < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hitSurface = GetSurface(MeshSurfaceIndexes[hit.triangle]);
|
||||
auto portal = hitSurface->portalIndex;
|
||||
|
||||
if (!portal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto& transformation = Portals[portal];
|
||||
|
||||
auto travelDist = hit.fraction * maxDist + 2.0f;
|
||||
if (travelDist >= maxDist)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
origin = transformation.TransformPosition(origin + direction * travelDist);
|
||||
direction = transformation.TransformRotation(direction);
|
||||
maxDist -= travelDist;
|
||||
}
|
||||
|
||||
return hitSurface; // I hit something
|
||||
}
|
||||
|
||||
protected:
|
||||
void BuildSmoothingGroups()
|
||||
{
|
||||
TArray<LevelMeshSmoothingGroup> SmoothingGroups;
|
||||
|
|
@ -346,6 +319,7 @@ protected:
|
|||
for (int i = 0, count = GetSurfaceCount(); i < count; i++)
|
||||
{
|
||||
auto targetSurface = GetSurface(i);
|
||||
targetSurface->tileSurfaces.Clear();
|
||||
for (LevelMeshSurface* surface : SmoothingGroups[targetSurface->smoothingGroupIndex].surfaces)
|
||||
{
|
||||
FVector2 minUV = ToUV(surface->bounds.min, targetSurface);
|
||||
|
|
@ -358,6 +332,7 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FVector2 ToUV(const FVector3& vert, const LevelMeshSurface* targetSurface)
|
||||
{
|
||||
FVector3 localPos = vert - targetSurface->translateWorldToLocal;
|
||||
|
|
@ -366,3 +341,73 @@ protected:
|
|||
return FVector2(u, v);
|
||||
}
|
||||
};
|
||||
|
||||
class LevelMesh
|
||||
{
|
||||
public:
|
||||
virtual ~LevelMesh() = default;
|
||||
|
||||
std::unique_ptr<LevelSubmesh> StaticMesh = std::make_unique<LevelSubmesh>();
|
||||
std::unique_ptr<LevelSubmesh> DynamicMesh = std::make_unique<LevelSubmesh>();
|
||||
|
||||
virtual int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { return 0; }
|
||||
|
||||
LevelMeshSurfaceStats GatherSurfacePixelStats()
|
||||
{
|
||||
LevelMeshSurfaceStats stats;
|
||||
StaticMesh->GatherSurfacePixelStats(stats);
|
||||
DynamicMesh->GatherSurfacePixelStats(stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
// Map defaults
|
||||
FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f);
|
||||
FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist)
|
||||
{
|
||||
maxDist = std::max(maxDist - 10.0f, 0.0f);
|
||||
|
||||
FVector3 origin = start;
|
||||
|
||||
LevelMeshSurface* hitSurface = nullptr;
|
||||
|
||||
while (true)
|
||||
{
|
||||
FVector3 end = origin + direction * maxDist;
|
||||
|
||||
TraceHit hit0 = TriangleMeshShape::find_first_hit(StaticMesh->Collision.get(), origin, end);
|
||||
TraceHit hit1 = TriangleMeshShape::find_first_hit(DynamicMesh->Collision.get(), origin, end);
|
||||
|
||||
LevelSubmesh* hitmesh = hit0.fraction < hit1.fraction ? StaticMesh.get() : DynamicMesh.get();
|
||||
TraceHit hit = hit0.fraction < hit1.fraction ? hit0 : hit1;
|
||||
|
||||
if (hit.triangle < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hitSurface = hitmesh->GetSurface(hitmesh->MeshSurfaceIndexes[hit.triangle]);
|
||||
auto portal = hitSurface->portalIndex;
|
||||
|
||||
if (!portal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto& transformation = hitmesh->Portals[portal];
|
||||
|
||||
auto travelDist = hit.fraction * maxDist + 2.0f;
|
||||
if (travelDist >= maxDist)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
origin = transformation.TransformPosition(origin + direction * travelDist);
|
||||
direction = transformation.TransformRotation(direction);
|
||||
maxDist -= travelDist;
|
||||
}
|
||||
|
||||
return hitSurface; // I hit something
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ void VkLightmap::Render()
|
|||
LightmapRaytracePC pc;
|
||||
pc.TileX = (float)selectedSurface.X;
|
||||
pc.TileY = (float)selectedSurface.Y;
|
||||
pc.SurfaceIndex = mesh->GetSurfaceIndex(targetSurface);
|
||||
pc.SurfaceIndex = mesh->StaticMesh->GetSurfaceIndex(targetSurface);
|
||||
pc.TextureSize = (float)bakeImageSize;
|
||||
pc.TileWidth = (float)targetSurface->texWidth;
|
||||
pc.TileHeight = (float)targetSurface->texHeight;
|
||||
|
|
|
|||
|
|
@ -32,26 +32,6 @@ VkRaytrace::VkRaytrace(VulkanRenderDevice* fb) : fb(fb)
|
|||
{
|
||||
useRayQuery = fb->GetDevice()->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME);
|
||||
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, 1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, -1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, 1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, 1.0f });
|
||||
|
||||
NullMesh.MeshVertexUVs.Resize(NullMesh.MeshVertices.Size());
|
||||
|
||||
for (int i = 0; i < 3 * 4; i++)
|
||||
NullMesh.MeshElements.Push(i);
|
||||
|
||||
NullMesh.Collision = std::make_unique<TriangleMeshShape>(NullMesh.MeshVertices.Data(), NullMesh.MeshVertices.Size(), NullMesh.MeshElements.Data(), NullMesh.MeshElements.Size());
|
||||
|
||||
SetLevelMesh(nullptr);
|
||||
}
|
||||
|
||||
|
|
@ -99,17 +79,19 @@ void VkRaytrace::CreateBuffers()
|
|||
{
|
||||
std::vector<CollisionNode> nodes = CreateCollisionNodes();
|
||||
|
||||
auto submesh = Mesh->StaticMesh.get();
|
||||
|
||||
// std430 alignment rules forces us to convert the vec3 to a vec4
|
||||
std::vector<SurfaceVertex> vertices;
|
||||
vertices.reserve(Mesh->MeshVertices.Size());
|
||||
for (int i = 0, count = Mesh->MeshVertices.Size(); i < count; ++i)
|
||||
vertices.push_back({ { Mesh->MeshVertices[i], 1.0f }, Mesh->MeshVertexUVs[i], float(i), i + 10000.0f});
|
||||
vertices.reserve(submesh->MeshVertices.Size());
|
||||
for (int i = 0, count = submesh->MeshVertices.Size(); i < count; ++i)
|
||||
vertices.push_back({ { submesh->MeshVertices[i], 1.0f }, submesh->MeshVertexUVs[i], float(i), i + 10000.0f});
|
||||
|
||||
CollisionNodeBufferHeader nodesHeader;
|
||||
nodesHeader.root = Mesh->Collision->get_root();
|
||||
nodesHeader.root = submesh->Collision->get_root();
|
||||
|
||||
TArray<PortalInfo> portalInfo;
|
||||
for (auto& portal : Mesh->Portals)
|
||||
for (auto& portal : submesh->Portals)
|
||||
{
|
||||
PortalInfo info;
|
||||
info.transformation = portal.transformation;
|
||||
|
|
@ -117,9 +99,9 @@ void VkRaytrace::CreateBuffers()
|
|||
}
|
||||
|
||||
TArray<SurfaceInfo> surfaceInfo;
|
||||
for (int i = 0, count = Mesh->GetSurfaceCount(); i < count; i++)
|
||||
for (int i = 0, count = submesh->GetSurfaceCount(); i < count; i++)
|
||||
{
|
||||
LevelMeshSurface* surface = Mesh->GetSurface(i);
|
||||
LevelMeshSurface* surface = submesh->GetSurface(i);
|
||||
|
||||
SurfaceInfo info;
|
||||
info.Normal = surface->plane.XYZ();
|
||||
|
|
@ -162,7 +144,7 @@ void VkRaytrace::CreateBuffers()
|
|||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||
.Size((size_t)Mesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.Size((size_t)submesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.DebugName("IndexBuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
|
|
@ -174,7 +156,7 @@ void VkRaytrace::CreateBuffers()
|
|||
|
||||
SurfaceIndexBuffer = BufferBuilder()
|
||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||
.Size(Mesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.Size(submesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.DebugName("SurfaceBuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
|
|
@ -192,9 +174,9 @@ void VkRaytrace::CreateBuffers()
|
|||
|
||||
auto transferBuffer = BufferTransfer()
|
||||
.AddBuffer(VertexBuffer.get(), vertices.data(), vertices.size() * sizeof(SurfaceVertex))
|
||||
.AddBuffer(IndexBuffer.get(), Mesh->MeshElements.Data(), (size_t)Mesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.AddBuffer(IndexBuffer.get(), submesh->MeshElements.Data(), (size_t)submesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.AddBuffer(NodeBuffer.get(), &nodesHeader, sizeof(CollisionNodeBufferHeader), nodes.data(), nodes.size() * sizeof(CollisionNode))
|
||||
.AddBuffer(SurfaceIndexBuffer.get(), Mesh->MeshSurfaceIndexes.Data(), Mesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.AddBuffer(SurfaceIndexBuffer.get(), submesh->MeshSurfaceIndexes.Data(), submesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.AddBuffer(SurfaceBuffer.get(), surfaceInfo.Data(), surfaceInfo.Size() * sizeof(SurfaceInfo))
|
||||
.AddBuffer(PortalBuffer.get(), portalInfo.Data(), portalInfo.Size() * sizeof(PortalInfo))
|
||||
.Execute(fb->GetDevice(), fb->GetCommands()->GetTransferCommands());
|
||||
|
|
@ -208,6 +190,8 @@ void VkRaytrace::CreateBuffers()
|
|||
|
||||
void VkRaytrace::CreateStaticBLAS()
|
||||
{
|
||||
auto submesh = Mesh->StaticMesh.get();
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
||||
VkAccelerationStructureGeometryKHR accelStructBLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
||||
VkAccelerationStructureGeometryKHR* geometries[] = { &accelStructBLDesc };
|
||||
|
|
@ -222,7 +206,7 @@ void VkRaytrace::CreateStaticBLAS()
|
|||
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(SurfaceVertex);
|
||||
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = IndexBuffer->GetDeviceAddress();
|
||||
accelStructBLDesc.geometry.triangles.maxVertex = Mesh->MeshVertices.Size() - 1;
|
||||
accelStructBLDesc.geometry.triangles.maxVertex = submesh->MeshVertices.Size() - 1;
|
||||
|
||||
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
|
|
@ -230,7 +214,7 @@ void VkRaytrace::CreateStaticBLAS()
|
|||
buildInfo.geometryCount = 1;
|
||||
buildInfo.ppGeometries = geometries;
|
||||
|
||||
uint32_t maxPrimitiveCount = Mesh->MeshElements.Size() / 3;
|
||||
uint32_t maxPrimitiveCount = submesh->MeshElements.Size() / 3;
|
||||
|
||||
VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR };
|
||||
vkGetAccelerationStructureBuildSizesKHR(fb->GetDevice()->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo);
|
||||
|
|
@ -428,9 +412,11 @@ void VkRaytrace::CreateTopLevelAS()
|
|||
|
||||
std::vector<CollisionNode> VkRaytrace::CreateCollisionNodes()
|
||||
{
|
||||
auto submesh = Mesh->StaticMesh.get();
|
||||
|
||||
std::vector<CollisionNode> nodes;
|
||||
nodes.reserve(Mesh->Collision->get_nodes().size());
|
||||
for (const auto& node : Mesh->Collision->get_nodes())
|
||||
nodes.reserve(submesh->Collision->get_nodes().size());
|
||||
for (const auto& node : submesh->Collision->get_nodes())
|
||||
{
|
||||
CollisionNode info;
|
||||
info.center = node.aabb.Center;
|
||||
|
|
|
|||
|
|
@ -480,9 +480,9 @@ void VulkanRenderDevice::BeginFrame()
|
|||
levelMeshChanged = false;
|
||||
mRaytrace->SetLevelMesh(levelMesh);
|
||||
|
||||
if (levelMesh && levelMesh->GetSurfaceCount() > 0)
|
||||
if (levelMesh && levelMesh->StaticMesh->GetSurfaceCount() > 0)
|
||||
{
|
||||
GetTextureManager()->CreateLightmap(levelMesh->LMTextureSize, levelMesh->LMTextureCount, std::move(levelMesh->LMTextureData));
|
||||
GetTextureManager()->CreateLightmap(levelMesh->StaticMesh->LMTextureSize, levelMesh->StaticMesh->LMTextureCount, std::move(levelMesh->StaticMesh->LMTextureData));
|
||||
GetLightmap()->SetLevelMesh(levelMesh);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2998,7 +2998,7 @@ void MapLoader::InitLevelMesh(MapData* map)
|
|||
}
|
||||
else
|
||||
{
|
||||
Level->levelMesh->Surfaces.Clear(); // Temp hack that disables lightmapping
|
||||
Level->levelMesh->DisableLightmaps();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3058,7 +3058,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
|
||||
if (surface->ControlSector == sec)
|
||||
{
|
||||
return Level->levelMesh->GetSurfaceIndex(surface);
|
||||
return Level->levelMesh->StaticMesh->GetSurfaceIndex(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3085,7 +3085,9 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
TArray<SurfaceEntry> zdraySurfaces;
|
||||
zdraySurfaces.Reserve(numSurfaces);
|
||||
|
||||
for (auto& surface : Level->levelMesh->Surfaces)
|
||||
auto submesh = static_cast<DoomLevelSubmesh*>(Level->levelMesh->StaticMesh.get());
|
||||
|
||||
for (auto& surface : submesh->Surfaces)
|
||||
{
|
||||
surface.needsUpdate = false; // let's consider everything valid until we make a mistake trying to change this surface
|
||||
|
||||
|
|
@ -3129,7 +3131,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (i >= Level->levelMesh->Surfaces.Size())
|
||||
if (i >= submesh->Surfaces.Size())
|
||||
{
|
||||
errors = true;
|
||||
if (developer >= 1)
|
||||
|
|
@ -3139,15 +3141,15 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
continue;
|
||||
}
|
||||
|
||||
auto levelSurface = &Level->levelMesh->Surfaces[i];
|
||||
auto levelSurface = &submesh->Surfaces[i];
|
||||
|
||||
if (levelSurface->Type != surface.type || levelSurface->typeIndex != surface.typeIndex || levelSurface->ControlSector != controlSector)
|
||||
{
|
||||
auto internalIndex = findSurfaceIndex(surface.type, surface.typeIndex, controlSector);
|
||||
|
||||
if (internalIndex < Level->levelMesh->Surfaces.Size())
|
||||
if (internalIndex < submesh->Surfaces.Size())
|
||||
{
|
||||
levelSurface = &Level->levelMesh->Surfaces[internalIndex];
|
||||
levelSurface = &submesh->Surfaces[internalIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3166,7 +3168,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
(*ptr)++;
|
||||
if (developer >= 1)
|
||||
{
|
||||
Printf(PRINT_HIGH, "Lightmap lump surface index %d is referencing surface %d (ref count: %d). Surface type:%d, typeindex:%d, controlsector:%d\n", i, Level->levelMesh->GetSurfaceIndex(levelSurface), *ptr, surface.type, surface.typeIndex, surface.controlSector);
|
||||
Printf(PRINT_HIGH, "Lightmap lump surface index %d is referencing surface %d (ref count: %d). Surface type:%d, typeindex:%d, controlsector:%d\n", i, submesh->GetSurfaceIndex(levelSurface), *ptr, surface.type, surface.typeIndex, surface.controlSector);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -3201,11 +3203,11 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
fr.Read(&zdrayUvs[0], numTexCoords * 2 * sizeof(float));
|
||||
|
||||
// Load lightmap textures
|
||||
const auto textureSize = Level->levelMesh->LMTextureSize;
|
||||
Level->levelMesh->LMTextureData.Resize(Level->levelMesh->LMTextureCount * textureSize * textureSize * 3);
|
||||
const auto textureSize = submesh->LMTextureSize;
|
||||
submesh->LMTextureData.Resize(submesh->LMTextureCount * textureSize * textureSize * 3);
|
||||
|
||||
auto pixels = &Level->levelMesh->LMTextureData[0];
|
||||
for (int i = 0, count = Level->levelMesh->LMTextureData.Size(); i < count; i += 3)
|
||||
auto pixels = &submesh->LMTextureData[0];
|
||||
for (int i = 0, count = submesh->LMTextureData.Size(); i < count; i += 3)
|
||||
{
|
||||
pixels[i] = floatToHalf(0.0);
|
||||
pixels[i + 1] = floatToHalf(0.0);
|
||||
|
|
@ -3213,14 +3215,14 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
}
|
||||
|
||||
#if 0 // debug surface mapping
|
||||
for (auto& surface : Level->levelMesh->Surfaces)
|
||||
for (auto& surface : submesh->Surfaces)
|
||||
{
|
||||
int dstX = surface.atlasX;
|
||||
int dstY = surface.atlasY;
|
||||
int dstPage = surface.atlasPageIndex;
|
||||
|
||||
// copy pixels
|
||||
uint16_t* dst = &Level->levelMesh->LMTextureData[dstPage * textureSize * textureSize * 3];
|
||||
uint16_t* dst = &submesh->LMTextureData[dstPage * textureSize * textureSize * 3];
|
||||
|
||||
uint32_t srcIndex = 0;
|
||||
|
||||
|
|
@ -3271,7 +3273,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
const int dstPage = realSurface.atlasPageIndex;
|
||||
|
||||
// Sanity checks
|
||||
if (dstX < 0 || dstY < 0 || dstX + surface.width > textureSize || dstY + surface.height > textureSize || dstPage >= Level->levelMesh->LMTextureCount)
|
||||
if (dstX < 0 || dstY < 0 || dstX + surface.width > textureSize || dstY + surface.height > textureSize || dstPage >= submesh->LMTextureCount)
|
||||
{
|
||||
errors = true;
|
||||
if (developer >= 1)
|
||||
|
|
@ -3307,7 +3309,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
uint32_t srcIndex = 0;
|
||||
uint16_t* src = &textureData[srcPixelOffset];
|
||||
|
||||
uint16_t* dst = &Level->levelMesh->LMTextureData[realSurface.atlasPageIndex * textureSize * textureSize * 3];
|
||||
uint16_t* dst = &submesh->LMTextureData[realSurface.atlasPageIndex * textureSize * textureSize * 3];
|
||||
|
||||
int endY = realSurface.atlasY + realSurface.texHeight;
|
||||
int endX = realSurface.atlasX + realSurface.texWidth;
|
||||
|
|
@ -3330,7 +3332,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
{
|
||||
auto& realSurface = *surface.targetSurface;
|
||||
|
||||
auto* UVs = &Level->levelMesh->LightmapUvs[realSurface.startUvIndex];
|
||||
auto* UVs = &submesh->LightmapUvs[realSurface.startUvIndex];
|
||||
auto* newUVs = &zdrayUvs[surface.uvOffset];
|
||||
|
||||
for (uint32_t i = 0; i < surface.uvCount; ++i)
|
||||
|
|
@ -3359,7 +3361,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
if (developer >= 3)
|
||||
{
|
||||
int loadedSurfaces = 0;
|
||||
for (auto& surface : Level->levelMesh->Surfaces)
|
||||
for (auto& surface : submesh->Surfaces)
|
||||
{
|
||||
if (!surface.needsUpdate)
|
||||
{
|
||||
|
|
@ -3367,7 +3369,7 @@ bool MapLoader::LoadLightmap(MapData* map)
|
|||
}
|
||||
}
|
||||
|
||||
Printf(PRINT_HIGH, "%d/%d surfaces were successfully loaded from lightmap.\n", loadedSurfaces, Level->levelMesh->Surfaces.Size());
|
||||
Printf(PRINT_HIGH, "%d/%d surfaces were successfully loaded from lightmap.\n", loadedSurfaces, submesh->Surfaces.Size());
|
||||
}
|
||||
|
||||
if (errors && developer <= 0)
|
||||
|
|
@ -3708,7 +3710,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
|||
if (!Level->IsReentering())
|
||||
Level->FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them.
|
||||
|
||||
Level->levelMesh->CreatePortals(); // [RaveYard]: needs portal data, but at the same time intializing the level mesh here breaks floor/ceiling planes!
|
||||
static_cast<DoomLevelSubmesh*>(Level->levelMesh->StaticMesh.get())->CreatePortals(); // [RaveYard]: needs portal data, but at the same time intializing the level mesh here breaks floor/ceiling planes!
|
||||
|
||||
Level->aabbTree = new DoomLevelAABBTree(Level);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ ADD_STAT(lightmap)
|
|||
return out;
|
||||
}
|
||||
|
||||
uint32_t atlasPixelCount = levelMesh->AtlasPixelCount();
|
||||
uint32_t atlasPixelCount = levelMesh->StaticMesh->AtlasPixelCount();
|
||||
auto stats = levelMesh->GatherSurfacePixelStats();
|
||||
|
||||
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%%",
|
||||
|
|
@ -67,13 +67,13 @@ CCMD(invalidatelightmap)
|
|||
if (!RequireLightmap()) return;
|
||||
|
||||
int count = 0;
|
||||
for (auto& surface : level.levelMesh->Surfaces)
|
||||
for (auto& surface : static_cast<DoomLevelSubmesh*>(level.levelMesh->StaticMesh.get())->Surfaces)
|
||||
{
|
||||
if (!surface.needsUpdate)
|
||||
++count;
|
||||
surface.needsUpdate = true;
|
||||
}
|
||||
Printf("Marked %d out of %d surfaces for update.\n", count, level.levelMesh->Surfaces.Size());
|
||||
Printf("Marked %d out of %d surfaces for update.\n", count, level.levelMesh->StaticMesh->GetSurfaceCount());
|
||||
}
|
||||
|
||||
void PrintSurfaceInfo(const DoomLevelMeshSurface* surface)
|
||||
|
|
@ -82,7 +82,7 @@ void PrintSurfaceInfo(const DoomLevelMeshSurface* surface)
|
|||
|
||||
auto gameTexture = TexMan.GameByIndex(surface->texture.GetIndex());
|
||||
|
||||
Printf("Surface %d (%p)\n Type: %d, TypeIndex: %d, ControlSector: %d\n", level.levelMesh->GetSurfaceIndex(surface), surface, surface->Type, surface->typeIndex, surface->ControlSector ? surface->ControlSector->Index() : -1);
|
||||
Printf("Surface %d (%p)\n Type: %d, TypeIndex: %d, ControlSector: %d\n", level.levelMesh->StaticMesh->GetSurfaceIndex(surface), surface, surface->Type, surface->typeIndex, surface->ControlSector ? surface->ControlSector->Index() : -1);
|
||||
Printf(" Atlas page: %d, x:%d, y:%d\n", surface->atlasPageIndex, surface->atlasX, surface->atlasY);
|
||||
Printf(" Pixels: %dx%d (area: %d)\n", surface->texWidth, surface->texHeight, surface->Area());
|
||||
Printf(" Sample dimension: %d\n", surface->sampleDimension);
|
||||
|
|
@ -134,10 +134,12 @@ CCMD(surfaceinfo)
|
|||
|
||||
EXTERN_CVAR(Float, lm_scale);
|
||||
|
||||
DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap)
|
||||
void DoomLevelSubmesh::CreateStatic(FLevelLocals& doomMap)
|
||||
{
|
||||
SunColor = doomMap.SunColor; // TODO keep only one copy?
|
||||
SunDirection = doomMap.SunDirection;
|
||||
MeshVertices.Clear();
|
||||
MeshVertexUVs.Clear();
|
||||
MeshElements.Clear();
|
||||
|
||||
LightmapSampleDistance = doomMap.LightmapSampleDistance;
|
||||
|
||||
BuildSectorGroups(doomMap);
|
||||
|
|
@ -151,7 +153,7 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap)
|
|||
|
||||
for (size_t i = 0; i < Surfaces.Size(); i++)
|
||||
{
|
||||
DoomLevelMeshSurface &s = Surfaces[i];
|
||||
DoomLevelMeshSurface& s = Surfaces[i];
|
||||
int numVerts = s.numVerts;
|
||||
unsigned int pos = s.startVertIndex;
|
||||
FVector3* verts = &MeshVertices[pos];
|
||||
|
|
@ -201,10 +203,27 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap)
|
|||
|
||||
SetupLightmapUvs(doomMap);
|
||||
|
||||
Collision = std::make_unique<TriangleMeshShape>(MeshVertices.Data(), MeshVertices.Size(), MeshElements.Data(), MeshElements.Size());
|
||||
UpdateCollision();
|
||||
}
|
||||
|
||||
void DoomLevelMesh::BuildSectorGroups(const FLevelLocals& doomMap)
|
||||
void DoomLevelSubmesh::CreateDynamic(FLevelLocals& doomMap)
|
||||
{
|
||||
LightmapSampleDistance = doomMap.LightmapSampleDistance;
|
||||
}
|
||||
|
||||
DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap)
|
||||
{
|
||||
SunColor = doomMap.SunColor; // TODO keep only one copy?
|
||||
SunDirection = doomMap.SunDirection;
|
||||
|
||||
StaticMesh = std::make_unique<DoomLevelSubmesh>();
|
||||
DynamicMesh = std::make_unique<DoomLevelSubmesh>();
|
||||
|
||||
static_cast<DoomLevelSubmesh*>(StaticMesh.get())->CreateStatic(doomMap);
|
||||
static_cast<DoomLevelSubmesh*>(DynamicMesh.get())->CreateDynamic(doomMap);
|
||||
}
|
||||
|
||||
void DoomLevelSubmesh::BuildSectorGroups(const FLevelLocals& doomMap)
|
||||
{
|
||||
int groupIndex = 0;
|
||||
|
||||
|
|
@ -253,7 +272,7 @@ void DoomLevelMesh::BuildSectorGroups(const FLevelLocals& doomMap)
|
|||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreatePortals()
|
||||
void DoomLevelSubmesh::CreatePortals()
|
||||
{
|
||||
std::map<LevelMeshPortal, int, IdenticalPortalComparator> transformationIndices; // TODO use the list of portals from the level to avoids duplicates?
|
||||
transformationIndices.emplace(LevelMeshPortal{}, 0); // first portal is an identity matrix
|
||||
|
|
@ -417,7 +436,7 @@ int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLi
|
|||
meshlight.Color.Z = light->GetBlue() * (1.0f / 255.0f);
|
||||
|
||||
if (light->Sector)
|
||||
meshlight.SectorGroup = sectorGroup[light->Sector->Index()];
|
||||
meshlight.SectorGroup = static_cast<DoomLevelSubmesh*>(StaticMesh.get())->sectorGroup[light->Sector->Index()];
|
||||
else
|
||||
meshlight.SectorGroup = 0;
|
||||
}
|
||||
|
|
@ -428,142 +447,7 @@ int DoomLevelMesh::AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLi
|
|||
return listpos;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void DoomLevelMesh::PropagateLight(const LevelMeshLight* light, std::set<LevelMeshPortal, RecursivePortalComparator>& touchedPortals, int lightPropagationRecursiveDepth)
|
||||
{
|
||||
if (++lightPropagationRecursiveDepth > 32) // TODO is this too much?
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SphereShape sphere;
|
||||
sphere.center = FVector3(light->RelativeOrigin);
|
||||
sphere.radius = light->Radius;
|
||||
std::set<LevelMeshPortal, RecursivePortalComparator> portalsToErase;
|
||||
for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere))
|
||||
{
|
||||
auto& surface = Surfaces[MeshSurfaceIndexes[triangleIndex]];
|
||||
|
||||
if (light->SectorGroup == surface.sectorGroup && IsInFrontOfPlane(surface.plane, light->RelativeOrigin))
|
||||
{
|
||||
if (surface.portalIndex >= 0)
|
||||
{
|
||||
auto& portal = Portals[surface.portalIndex];
|
||||
|
||||
if (touchedPortals.insert(portal).second)
|
||||
{
|
||||
auto newLight = std::make_unique<LevelMeshLight>(*light);
|
||||
auto fakeLight = newLight.get();
|
||||
Lights.push_back(std::move(newLight));
|
||||
|
||||
fakeLight->RelativeOrigin = portal.TransformPosition(light->RelativeOrigin);
|
||||
fakeLight->SectorGroup = portal.targetSectorGroup;
|
||||
|
||||
PropagateLight(fakeLight, touchedPortals, lightPropagationRecursiveDepth);
|
||||
portalsToErase.insert(portal);
|
||||
}
|
||||
}
|
||||
|
||||
// Add light to the list if it isn't already there
|
||||
// TODO in order for this to work the light list be fed from global light buffer? Or just somehow de-duplicate portals?
|
||||
bool found = false;
|
||||
for (const LevelMeshLight* light2 : surface.LightList)
|
||||
{
|
||||
if (light2 == light)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
surface.LightList.push_back(light);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& portal : portalsToErase)
|
||||
{
|
||||
touchedPortals.erase(portal); // Dear me: I wonder what was the reason for all of this.
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateLightList()
|
||||
{
|
||||
std::set<FDynamicLight*> lightList; // bit silly ain't it?
|
||||
|
||||
Lights.clear();
|
||||
for (auto& surface : Surfaces)
|
||||
{
|
||||
surface.LightList.clear();
|
||||
|
||||
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
|
||||
{
|
||||
auto node = surface.Subsector->section->lighthead;
|
||||
|
||||
while (node)
|
||||
{
|
||||
FDynamicLight* light = node->lightsource;
|
||||
|
||||
if (light->Trace())
|
||||
{
|
||||
if (lightList.insert(light).second)
|
||||
{
|
||||
DVector3 pos = light->Pos; //light->PosRelative(portalgroup);
|
||||
|
||||
LevelMeshLight meshlight;
|
||||
meshlight.Origin = { (float)pos.X, (float)pos.Y, (float)pos.Z };
|
||||
meshlight.RelativeOrigin = meshlight.Origin;
|
||||
meshlight.Radius = (float)light->GetRadius();
|
||||
meshlight.Intensity = (float)light->target->Alpha;
|
||||
if (light->IsSpot())
|
||||
{
|
||||
meshlight.InnerAngleCos = (float)light->pSpotInnerAngle->Cos();
|
||||
meshlight.OuterAngleCos = (float)light->pSpotOuterAngle->Cos();
|
||||
|
||||
DAngle negPitch = -*light->pPitch;
|
||||
DAngle Angle = light->target->Angles.Yaw;
|
||||
double xzLen = negPitch.Cos();
|
||||
meshlight.SpotDir.X = float(-Angle.Cos() * xzLen);
|
||||
meshlight.SpotDir.Y = float(-Angle.Sin() * xzLen);
|
||||
meshlight.SpotDir.Z = float(-negPitch.Sin());
|
||||
}
|
||||
else
|
||||
{
|
||||
meshlight.InnerAngleCos = -1.0f;
|
||||
meshlight.OuterAngleCos = -1.0f;
|
||||
meshlight.SpotDir.X = 0.0f;
|
||||
meshlight.SpotDir.Y = 0.0f;
|
||||
meshlight.SpotDir.Z = 0.0f;
|
||||
}
|
||||
meshlight.Color.X = light->GetRed() * (1.0f / 255.0f);
|
||||
meshlight.Color.Y = light->GetGreen() * (1.0f / 255.0f);
|
||||
meshlight.Color.Z = light->GetBlue() * (1.0f / 255.0f);
|
||||
|
||||
if (light->Sector)
|
||||
meshlight.SectorGroup = sectorGroup[light->Sector->Index()];
|
||||
else
|
||||
meshlight.SectorGroup = 0;
|
||||
|
||||
Lights.push_back(std::make_unique<LevelMeshLight>(meshlight));
|
||||
}
|
||||
}
|
||||
|
||||
node = node->nextLight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<LevelMeshPortal, RecursivePortalComparator> touchedPortals;
|
||||
touchedPortals.insert(Portals[0]);
|
||||
|
||||
for (int i = 0, count = (int)Lights.size(); i < count; ++i) // The array expands as the lights are duplicated/propagated
|
||||
{
|
||||
PropagateLight(Lights[i].get(), touchedPortals, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void DoomLevelMesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap)
|
||||
void DoomLevelSubmesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap)
|
||||
{
|
||||
// You have no idea how long this took me to figure out...
|
||||
|
||||
|
|
@ -636,25 +520,9 @@ void DoomLevelMesh::BindLightmapSurfacesToGeometry(FLevelLocals& doomMap)
|
|||
SetSideLightmap(&surface);
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime helper
|
||||
for (auto& surface : Surfaces)
|
||||
{
|
||||
if (surface.ControlSector)
|
||||
{
|
||||
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
|
||||
{
|
||||
XFloorToSurface[surface.Subsector->sector].Push(&surface);
|
||||
}
|
||||
else if (surface.Type == ST_MIDDLESIDE)
|
||||
{
|
||||
XFloorToSurfaceSides[surface.ControlSector].Push(&surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::SetSubsectorLightmap(DoomLevelMeshSurface* surface)
|
||||
void DoomLevelSubmesh::SetSubsectorLightmap(DoomLevelMeshSurface* surface)
|
||||
{
|
||||
if (!surface->ControlSector)
|
||||
{
|
||||
|
|
@ -675,7 +543,7 @@ void DoomLevelMesh::SetSubsectorLightmap(DoomLevelMeshSurface* surface)
|
|||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::SetSideLightmap(DoomLevelMeshSurface* surface)
|
||||
void DoomLevelSubmesh::SetSideLightmap(DoomLevelMeshSurface* surface)
|
||||
{
|
||||
if (!surface->ControlSector)
|
||||
{
|
||||
|
|
@ -706,7 +574,7 @@ void DoomLevelMesh::SetSideLightmap(DoomLevelMeshSurface* surface)
|
|||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
|
||||
void DoomLevelSubmesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
|
||||
{
|
||||
sector_t *front;
|
||||
sector_t *back;
|
||||
|
|
@ -1064,7 +932,7 @@ void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
|
|||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub, sector_t *sector, sector_t *controlSector, int typeIndex)
|
||||
void DoomLevelSubmesh::CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub, sector_t *sector, sector_t *controlSector, int typeIndex)
|
||||
{
|
||||
DoomLevelMeshSurface surf;
|
||||
|
||||
|
|
@ -1117,7 +985,7 @@ void DoomLevelMesh::CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub,
|
|||
Surfaces.Push(surf);
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateCeilingSurface(FLevelLocals& doomMap, subsector_t* sub, sector_t* sector, sector_t* controlSector, int typeIndex)
|
||||
void DoomLevelSubmesh::CreateCeilingSurface(FLevelLocals& doomMap, subsector_t* sub, sector_t* sector, sector_t* controlSector, int typeIndex)
|
||||
{
|
||||
DoomLevelMeshSurface surf;
|
||||
|
||||
|
|
@ -1170,7 +1038,7 @@ void DoomLevelMesh::CreateCeilingSurface(FLevelLocals& doomMap, subsector_t* sub
|
|||
Surfaces.Push(surf);
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateSubsectorSurfaces(FLevelLocals &doomMap)
|
||||
void DoomLevelSubmesh::CreateSubsectorSurfaces(FLevelLocals &doomMap)
|
||||
{
|
||||
for (unsigned int i = 0; i < doomMap.subsectors.Size(); i++)
|
||||
{
|
||||
|
|
@ -1196,36 +1064,36 @@ void DoomLevelMesh::CreateSubsectorSurfaces(FLevelLocals &doomMap)
|
|||
}
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::IsTopSideSky(sector_t* frontsector, sector_t* backsector, side_t* side)
|
||||
bool DoomLevelSubmesh::IsTopSideSky(sector_t* frontsector, sector_t* backsector, side_t* side)
|
||||
{
|
||||
return IsSkySector(frontsector, sector_t::ceiling) && IsSkySector(backsector, sector_t::ceiling);
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::IsTopSideVisible(side_t* side)
|
||||
bool DoomLevelSubmesh::IsTopSideVisible(side_t* side)
|
||||
{
|
||||
auto tex = TexMan.GetGameTexture(side->GetTexture(side_t::top), true);
|
||||
return tex && tex->isValid();
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::IsBottomSideVisible(side_t* side)
|
||||
bool DoomLevelSubmesh::IsBottomSideVisible(side_t* side)
|
||||
{
|
||||
auto tex = TexMan.GetGameTexture(side->GetTexture(side_t::bottom), true);
|
||||
return tex && tex->isValid();
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::IsSkySector(sector_t* sector, int plane)
|
||||
bool DoomLevelSubmesh::IsSkySector(sector_t* sector, int plane)
|
||||
{
|
||||
// plane is either sector_t::ceiling or sector_t::floor
|
||||
return sector->GetTexture(plane) == skyflatnum;
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::IsControlSector(sector_t* sector)
|
||||
bool DoomLevelSubmesh::IsControlSector(sector_t* sector)
|
||||
{
|
||||
//return sector->controlsector;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DoomLevelMesh::IsDegenerate(const FVector3 &v0, const FVector3 &v1, const FVector3 &v2)
|
||||
bool DoomLevelSubmesh::IsDegenerate(const FVector3 &v0, const FVector3 &v1, const FVector3 &v2)
|
||||
{
|
||||
// A degenerate triangle has a zero cross product for two of its sides.
|
||||
float ax = v1.X - v0.X;
|
||||
|
|
@ -1241,7 +1109,7 @@ bool DoomLevelMesh::IsDegenerate(const FVector3 &v0, const FVector3 &v1, const F
|
|||
return crosslengthsqr <= 1.e-6f;
|
||||
}
|
||||
|
||||
void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const
|
||||
void DoomLevelSubmesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const
|
||||
{
|
||||
auto f = fopen(objFilename.GetChars(), "w");
|
||||
|
||||
|
|
@ -1352,7 +1220,7 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
void DoomLevelMesh::SetupLightmapUvs(FLevelLocals& doomMap)
|
||||
void DoomLevelSubmesh::SetupLightmapUvs(FLevelLocals& doomMap)
|
||||
{
|
||||
LMTextureSize = 1024; // TODO cvar
|
||||
|
||||
|
|
@ -1366,7 +1234,7 @@ void DoomLevelMesh::SetupLightmapUvs(FLevelLocals& doomMap)
|
|||
CreateSurfaceTextureUVs(doomMap);
|
||||
}
|
||||
|
||||
void DoomLevelMesh::PackLightmapAtlas()
|
||||
void DoomLevelSubmesh::PackLightmapAtlas()
|
||||
{
|
||||
std::vector<LevelMeshSurface*> sortedSurfaces;
|
||||
sortedSurfaces.reserve(Surfaces.Size());
|
||||
|
|
@ -1388,7 +1256,7 @@ void DoomLevelMesh::PackLightmapAtlas()
|
|||
LMTextureCount = (int)packer.getNumPages();
|
||||
}
|
||||
|
||||
void DoomLevelMesh::FinishSurface(int lightmapTextureWidth, int lightmapTextureHeight, RectPacker& packer, LevelMeshSurface& surface)
|
||||
void DoomLevelSubmesh::FinishSurface(int lightmapTextureWidth, int lightmapTextureHeight, RectPacker& packer, LevelMeshSurface& surface)
|
||||
{
|
||||
int sampleWidth = surface.texWidth;
|
||||
int sampleHeight = surface.texHeight;
|
||||
|
|
@ -1410,7 +1278,7 @@ void DoomLevelMesh::FinishSurface(int lightmapTextureWidth, int lightmapTextureH
|
|||
surface.atlasY = y;
|
||||
}
|
||||
|
||||
BBox DoomLevelMesh::GetBoundsFromSurface(const LevelMeshSurface& surface) const
|
||||
BBox DoomLevelSubmesh::GetBoundsFromSurface(const LevelMeshSurface& surface) const
|
||||
{
|
||||
constexpr float M_INFINITY = 1e30f; // TODO cleanup
|
||||
|
||||
|
|
@ -1439,7 +1307,7 @@ BBox DoomLevelMesh::GetBoundsFromSurface(const LevelMeshSurface& surface) const
|
|||
return bounds;
|
||||
}
|
||||
|
||||
DoomLevelMesh::PlaneAxis DoomLevelMesh::BestAxis(const FVector4& p)
|
||||
DoomLevelSubmesh::PlaneAxis DoomLevelSubmesh::BestAxis(const FVector4& p)
|
||||
{
|
||||
float na = fabs(float(p.X));
|
||||
float nb = fabs(float(p.Y));
|
||||
|
|
@ -1458,7 +1326,7 @@ DoomLevelMesh::PlaneAxis DoomLevelMesh::BestAxis(const FVector4& p)
|
|||
return AXIS_XY;
|
||||
}
|
||||
|
||||
void DoomLevelMesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface)
|
||||
void DoomLevelSubmesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface)
|
||||
{
|
||||
BBox bounds;
|
||||
FVector3 roundedSize;
|
||||
|
|
@ -1574,7 +1442,7 @@ VSMatrix GetPlaneTextureRotationMatrix(FGameTexture* gltexture, const sector_t*
|
|||
// hw_walls.cpp
|
||||
void GetTexCoordInfo(FGameTexture* tex, FTexCoordInfo* tci, side_t* side, int texpos);
|
||||
|
||||
void DoomLevelMesh::CreateSurfaceTextureUVs(FLevelLocals& doomMap)
|
||||
void DoomLevelSubmesh::CreateSurfaceTextureUVs(FLevelLocals& doomMap)
|
||||
{
|
||||
auto toUv = [](const DoomLevelMeshSurface* targetSurface, FVector3 vert) {
|
||||
FVector3 localPos = vert - targetSurface->translateWorldToLocal;
|
||||
|
|
|
|||
|
|
@ -22,48 +22,35 @@ struct DoomLevelMeshSurface : public LevelMeshSurface
|
|||
float* TexCoords;
|
||||
};
|
||||
|
||||
class DoomLevelMesh : public LevelMesh
|
||||
class DoomLevelSubmesh : public LevelSubmesh
|
||||
{
|
||||
public:
|
||||
DoomLevelMesh(FLevelLocals &doomMap);
|
||||
|
||||
void CreatePortals();
|
||||
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const;
|
||||
void BindLightmapSurfacesToGeometry(FLevelLocals& doomMap);
|
||||
void PackLightmapAtlas();
|
||||
|
||||
bool TraceSky(const FVector3& start, FVector3 direction, float dist)
|
||||
{
|
||||
FVector3 end = start + direction * dist;
|
||||
auto surface = Trace(start, direction, dist);
|
||||
return surface && surface->bSky;
|
||||
}
|
||||
|
||||
int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) override;
|
||||
void CreateStatic(FLevelLocals& doomMap);
|
||||
void CreateDynamic(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()); }
|
||||
int GetSurfaceCount() override { return Surfaces.Size(); }
|
||||
|
||||
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const;
|
||||
|
||||
// Used by Maploader
|
||||
void BindLightmapSurfacesToGeometry(FLevelLocals& doomMap);
|
||||
void PackLightmapAtlas();
|
||||
void CreatePortals();
|
||||
void DisableLightmaps() { Surfaces.Clear(); } // Temp hack that disables lightmapping
|
||||
|
||||
TArray<DoomLevelMeshSurface> Surfaces;
|
||||
std::vector<std::unique_ptr<LevelMeshLight>> Lights;
|
||||
TArray<FVector2> LightmapUvs;
|
||||
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
|
||||
|
||||
// utility
|
||||
TArray<int> sectorGroup; // index is sector, value is sectorGroup
|
||||
|
||||
// runtime utility variables
|
||||
TMap<const sector_t*, TArray<DoomLevelMeshSurface*>> XFloorToSurface;
|
||||
TMap<const sector_t*, TArray<DoomLevelMeshSurface*>> XFloorToSurfaceSides;
|
||||
|
||||
private:
|
||||
void BuildSectorGroups(const FLevelLocals& doomMap);
|
||||
|
||||
void CreateSubsectorSurfaces(FLevelLocals &doomMap);
|
||||
void CreateSubsectorSurfaces(FLevelLocals& doomMap);
|
||||
void CreateCeilingSurface(FLevelLocals& doomMap, subsector_t* sub, sector_t* sector, sector_t* controlSector, int typeIndex);
|
||||
void CreateFloorSurface(FLevelLocals& doomMap, subsector_t* sub, sector_t* sector, sector_t* controlSector, int typeIndex);
|
||||
void CreateSideSurfaces(FLevelLocals &doomMap, side_t *side);
|
||||
void CreateSideSurfaces(FLevelLocals& doomMap, side_t* side);
|
||||
|
||||
void CreateSurfaceTextureUVs(FLevelLocals& doomMap);
|
||||
|
||||
|
|
@ -91,7 +78,7 @@ private:
|
|||
{
|
||||
return ToPlane(pt1, pt2, pt4);
|
||||
}
|
||||
else if(pt1.ApproximatelyEquals(pt2) || pt2.ApproximatelyEquals(pt3))
|
||||
else if (pt1.ApproximatelyEquals(pt2) || pt2.ApproximatelyEquals(pt3))
|
||||
{
|
||||
return ToPlane(pt1, pt3, pt4);
|
||||
}
|
||||
|
|
@ -99,13 +86,7 @@ private:
|
|||
return ToPlane(pt1, pt2, pt3);
|
||||
}
|
||||
|
||||
static FVector2 ToFVector2(const DVector2& v) { return FVector2((float)v.X, (float)v.Y); }
|
||||
static FVector3 ToFVector3(const DVector3& v) { return FVector3((float)v.X, (float)v.Y, (float)v.Z); }
|
||||
static FVector4 ToFVector4(const DVector4& v) { return FVector4((float)v.X, (float)v.Y, (float)v.Z, (float)v.W); }
|
||||
|
||||
static bool IsDegenerate(const FVector3 &v0, const FVector3 &v1, const FVector3 &v2);
|
||||
|
||||
// WIP internal lightmapper
|
||||
// Lightmapper
|
||||
|
||||
enum PlaneAxis
|
||||
{
|
||||
|
|
@ -121,4 +102,67 @@ private:
|
|||
|
||||
void BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface);
|
||||
void FinishSurface(int lightmapTextureWidth, int lightmapTextureHeight, RectPacker& packer, LevelMeshSurface& surface);
|
||||
|
||||
static bool IsDegenerate(const FVector3& v0, const FVector3& v1, const FVector3& v2);
|
||||
|
||||
static FVector2 ToFVector2(const DVector2& v) { return FVector2((float)v.X, (float)v.Y); }
|
||||
static FVector3 ToFVector3(const DVector3& v) { return FVector3((float)v.X, (float)v.Y, (float)v.Z); }
|
||||
static FVector4 ToFVector4(const DVector4& v) { return FVector4((float)v.X, (float)v.Y, (float)v.Z, (float)v.W); }
|
||||
};
|
||||
|
||||
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
|
||||
|
||||
class DoomLevelMesh : public LevelMesh
|
||||
{
|
||||
public:
|
||||
DoomLevelMesh(FLevelLocals &doomMap);
|
||||
|
||||
bool TraceSky(const FVector3& start, FVector3 direction, float dist)
|
||||
{
|
||||
FVector3 end = start + direction * dist;
|
||||
auto surface = Trace(start, direction, dist);
|
||||
return surface && surface->bSky;
|
||||
}
|
||||
|
||||
int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) override;
|
||||
|
||||
void PackLightmapAtlas()
|
||||
{
|
||||
static_cast<DoomLevelSubmesh*>(StaticMesh.get())->PackLightmapAtlas();
|
||||
}
|
||||
|
||||
void BindLightmapSurfacesToGeometry(FLevelLocals& doomMap)
|
||||
{
|
||||
static_cast<DoomLevelSubmesh*>(StaticMesh.get())->BindLightmapSurfacesToGeometry(doomMap);
|
||||
|
||||
// Runtime helper
|
||||
for (auto& surface : static_cast<DoomLevelSubmesh*>(StaticMesh.get())->Surfaces)
|
||||
{
|
||||
if (surface.ControlSector)
|
||||
{
|
||||
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
|
||||
{
|
||||
XFloorToSurface[surface.Subsector->sector].Push(&surface);
|
||||
}
|
||||
else if (surface.Type == ST_MIDDLESIDE)
|
||||
{
|
||||
XFloorToSurfaceSides[surface.ControlSector].Push(&surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisableLightmaps()
|
||||
{
|
||||
static_cast<DoomLevelSubmesh*>(StaticMesh.get())->DisableLightmaps();
|
||||
}
|
||||
|
||||
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const
|
||||
{
|
||||
static_cast<DoomLevelSubmesh*>(StaticMesh.get())->DumpMesh(objFilename, mtlFilename);
|
||||
}
|
||||
|
||||
// To do: remove these. Use ffloors on flats and sides to find the 3d surfaces as that is both faster and culls better
|
||||
TMap<const sector_t*, TArray<DoomLevelMeshSurface*>> XFloorToSurface;
|
||||
TMap<const sector_t*, TArray<DoomLevelMeshSurface*>> XFloorToSurfaceSides;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ void HWDrawInfo::UpdateLightmaps()
|
|||
{
|
||||
if (!outer && VisibleSurfaces.Size() < unsigned(lm_background_updates))
|
||||
{
|
||||
for (auto& e : level.levelMesh->Surfaces)
|
||||
for (auto& e : static_cast<DoomLevelSubmesh*>(level.levelMesh->StaticMesh.get())->Surfaces)
|
||||
{
|
||||
if (e.needsUpdate && !e.bSky && !e.portalIndex)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue