From 7bc2ed54360be39d76b784ad7829e823bbaf2099 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 29 Jan 2024 21:56:42 +0100 Subject: [PATCH] Remove the submesh class as that caused more problems than it solved --- src/CMakeLists.txt | 1 - .../hwrenderer/data/hw_levelmesh.cpp | 85 +-- .../rendering/hwrenderer/data/hw_levelmesh.h | 58 +- .../hwrenderer/data/hw_levelmeshsurface.h | 3 - .../hwrenderer/data/hw_lightmaptile.h | 2 +- src/common/rendering/vulkan/vk_levelmesh.cpp | 201 ++---- src/common/rendering/vulkan/vk_levelmesh.h | 15 +- .../rendering/vulkan/vk_lightmapper.cpp | 19 +- .../rendering/vulkan/vk_renderdevice.cpp | 4 +- .../rendering/vulkan/vk_renderstate.cpp | 14 +- src/maploader/maploader.cpp | 21 +- src/rendering/hwrenderer/doom_levelmesh.cpp | 631 +++++++++++++++++- src/rendering/hwrenderer/doom_levelmesh.h | 52 +- .../hwrenderer/doom_levelsubmesh.cpp | 627 ----------------- src/rendering/hwrenderer/doom_levelsubmesh.h | 71 -- src/rendering/hwrenderer/hw_vertexbuilder.cpp | 2 +- src/rendering/hwrenderer/scene/hw_decal.cpp | 4 +- .../hwrenderer/scene/hw_drawinfo.cpp | 4 +- src/rendering/hwrenderer/scene/hw_drawinfo.h | 3 +- .../hwrenderer/scene/hw_walls_vertex.cpp | 13 +- 20 files changed, 836 insertions(+), 994 deletions(-) delete mode 100644 src/rendering/hwrenderer/doom_levelsubmesh.cpp delete mode 100644 src/rendering/hwrenderer/doom_levelsubmesh.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6765c6001..7c9d31614 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -893,7 +893,6 @@ set (PCH_SOURCES rendering/hwrenderer/hw_vertexbuilder.cpp rendering/hwrenderer/doom_aabbtree.cpp rendering/hwrenderer/doom_levelmesh.cpp - rendering/hwrenderer/doom_levelsubmesh.cpp rendering/hwrenderer/hw_models.cpp rendering/hwrenderer/hw_precache.cpp rendering/hwrenderer/scene/hw_lighting.cpp diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp index b4a58345a..d8f52f4e0 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp @@ -7,6 +7,31 @@ LevelMesh::LevelMesh() // Default portal LevelMeshPortal portal; Portals.Push(portal); + + AddEmptyMesh(); + UpdateCollision(); +} + +void LevelMesh::AddEmptyMesh() +{ + // Default empty mesh (we can't make it completely empty since vulkan doesn't like that) + float minval = -100001.0f; + float maxval = -100000.0f; + Mesh.Vertices.Push({ minval, minval, minval }); + Mesh.Vertices.Push({ maxval, minval, minval }); + Mesh.Vertices.Push({ maxval, maxval, minval }); + Mesh.Vertices.Push({ minval, minval, minval }); + Mesh.Vertices.Push({ minval, maxval, minval }); + Mesh.Vertices.Push({ maxval, maxval, minval }); + Mesh.Vertices.Push({ minval, minval, maxval }); + Mesh.Vertices.Push({ maxval, minval, maxval }); + Mesh.Vertices.Push({ maxval, maxval, maxval }); + Mesh.Vertices.Push({ minval, minval, maxval }); + Mesh.Vertices.Push({ minval, maxval, maxval }); + Mesh.Vertices.Push({ maxval, maxval, maxval }); + + for (int i = 0; i < 3 * 4; i++) + Mesh.Indexes.Push(i); } LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, float maxDist) @@ -21,18 +46,14 @@ LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, fl { 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; + TraceHit hit = TriangleMeshShape::find_first_hit(Collision.get(), origin, end); if (hit.triangle < 0) { return nullptr; } - hitSurface = hitmesh->GetSurface(hitmesh->Mesh.SurfaceIndexes[hit.triangle]); + hitSurface = GetSurface(Mesh.SurfaceIndexes[hit.triangle]); int portal = hitSurface->PortalIndex; if (!portal) @@ -59,44 +80,6 @@ LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, fl LevelMeshTileStats LevelMesh::GatherTilePixelStats() { LevelMeshTileStats stats; - StaticMesh->GatherTilePixelStats(stats); - DynamicMesh->GatherTilePixelStats(stats); - return stats; -} - -///////////////////////////////////////////////////////////////////////////// - -LevelSubmesh::LevelSubmesh() -{ - // Default empty mesh (we can't make it completely empty since vulkan doesn't like that) - float minval = -100001.0f; - float maxval = -100000.0f; - Mesh.Vertices.Push({ minval, minval, minval }); - Mesh.Vertices.Push({ maxval, minval, minval }); - Mesh.Vertices.Push({ maxval, maxval, minval }); - Mesh.Vertices.Push({ minval, minval, minval }); - Mesh.Vertices.Push({ minval, maxval, minval }); - Mesh.Vertices.Push({ maxval, maxval, minval }); - Mesh.Vertices.Push({ minval, minval, maxval }); - Mesh.Vertices.Push({ maxval, minval, maxval }); - Mesh.Vertices.Push({ maxval, maxval, maxval }); - Mesh.Vertices.Push({ minval, minval, maxval }); - Mesh.Vertices.Push({ minval, maxval, maxval }); - Mesh.Vertices.Push({ maxval, maxval, maxval }); - - for (int i = 0; i < 3 * 4; i++) - Mesh.Indexes.Push(i); - - UpdateCollision(); -} - -void LevelSubmesh::UpdateCollision() -{ - Collision = std::make_unique(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size()); -} - -void LevelSubmesh::GatherTilePixelStats(LevelMeshTileStats& stats) -{ int count = GetSurfaceCount(); for (const LightmapTile& tile : LightmapTiles) { @@ -111,6 +94,12 @@ void LevelSubmesh::GatherTilePixelStats(LevelMeshTileStats& stats) } } stats.tiles.total += LightmapTiles.Size(); + return stats; +} + +void LevelMesh::UpdateCollision() +{ + Collision = std::make_unique(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size()); } struct LevelMeshPlaneGroup @@ -120,7 +109,7 @@ struct LevelMeshPlaneGroup std::vector surfaces; }; -void LevelSubmesh::BuildTileSurfaceLists() +void LevelMesh::BuildTileSurfaceLists() { // Plane group surface is to be rendered with TArray PlaneGroups; @@ -184,12 +173,12 @@ void LevelSubmesh::BuildTileSurfaceLists() if (surface != targetSurface && (maxUV.X < 0.0f || maxUV.Y < 0.0f || minUV.X > 1.0f || minUV.Y > 1.0f)) continue; // Bounding box not visible - tile->Surfaces.Push(surface); + tile->Surfaces.Push(GetSurfaceIndex(surface)); } } } -void LevelSubmesh::SetupTileTransforms() +void LevelMesh::SetupTileTransforms() { for (auto& tile : LightmapTiles) { @@ -197,7 +186,7 @@ void LevelSubmesh::SetupTileTransforms() } } -void LevelSubmesh::PackLightmapAtlas(int lightmapStartIndex) +void LevelMesh::PackLightmapAtlas(int lightmapStartIndex) { std::vector sortedTiles; sortedTiles.reserve(LightmapTiles.Size()); diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index ed6426782..994405f31 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -25,24 +25,49 @@ struct LevelSubmeshDrawRange int Count; }; -class LevelSubmesh +class LevelMesh { public: - LevelSubmesh(); - virtual ~LevelSubmesh() = default; + LevelMesh(); + virtual ~LevelMesh() = default; 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; } + + LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist); + + LevelMeshTileStats GatherTilePixelStats(); + + // Map defaults + FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f); + FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f); + + TArray Portals; struct { + // Vertex data TArray Vertices; - TArray Indexes; - TArray SurfaceIndexes; TArray UniformIndexes; + + // Surface info TArray Uniforms; TArray Materials; + + // Index data + TArray Indexes; + TArray SurfaceIndexes; + int DynamicIndexStart = 0; + + // Above data must not be resized beyond these limits as that's the size of the GPU buffers) + int MaxVertices = 0; + int MaxIndexes = 0; + int MaxSurfaces = 0; + int MaxUniforms = 0; + int MaxSurfaceIndexes = 0; + int MaxNodes = 0; } Mesh; std::unique_ptr Collision; @@ -62,32 +87,11 @@ public: uint32_t AtlasPixelCount() const { return uint32_t(LMTextureCount * LMTextureSize * LMTextureSize); } void UpdateCollision(); - void GatherTilePixelStats(LevelMeshTileStats& stats); void BuildTileSurfaceLists(); void SetupTileTransforms(); void PackLightmapAtlas(int lightmapStartIndex); -}; -class LevelMesh -{ -public: - LevelMesh(); - virtual ~LevelMesh() = default; - - std::unique_ptr StaticMesh = std::make_unique(); - std::unique_ptr DynamicMesh = std::make_unique(); - - virtual int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { return 0; } - - LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist); - - LevelMeshTileStats GatherTilePixelStats(); - - // Map defaults - FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f); - FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f); - - TArray Portals; + void AddEmptyMesh(); }; struct LevelMeshTileStats diff --git a/src/common/rendering/hwrenderer/data/hw_levelmeshsurface.h b/src/common/rendering/hwrenderer/data/hw_levelmeshsurface.h index 854ab7937..c933a6647 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmeshsurface.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmeshsurface.h @@ -7,14 +7,11 @@ #include "textureid.h" #include "textures.h" -class LevelSubmesh; class FGameTexture; struct LevelMeshSurface; struct LevelMeshSurface { - LevelSubmesh* Submesh = nullptr; - struct { unsigned int StartVertIndex = 0; diff --git a/src/common/rendering/hwrenderer/data/hw_lightmaptile.h b/src/common/rendering/hwrenderer/data/hw_lightmaptile.h index 0775c99bb..e7cbcc47d 100644 --- a/src/common/rendering/hwrenderer/data/hw_lightmaptile.h +++ b/src/common/rendering/hwrenderer/data/hw_lightmaptile.h @@ -45,7 +45,7 @@ struct LightmapTile LightmapTileBinding Binding; // Surfaces that are visible within the lightmap tile - TArray Surfaces; + TArray Surfaces; BBox Bounds; uint16_t SampleDimension = 0; diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index 9e172120c..9d59fb2e1 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -92,7 +92,7 @@ void VkLevelMesh::CreateVulkanObjects() .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT) .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); - CreateTopLevelAS(); + CreateTopLevelAS(DynamicBLAS.AccelStruct ? 2 : 1); // Finish building the accel struct before using it from the shaders PipelineBarrier() @@ -129,7 +129,8 @@ void VkLevelMesh::BeginFrame() deletelist->Add(std::move(TopLevelAS.TransferBuffer)); deletelist->Add(std::move(TopLevelAS.InstanceBuffer)); - DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Indexes.Size()); + if (Mesh->Mesh.DynamicIndexStart < (int)Mesh->Mesh.Indexes.Size()) + DynamicBLAS = CreateBLAS(true, Mesh->Mesh.DynamicIndexStart, Mesh->Mesh.Indexes.Size() - Mesh->Mesh.DynamicIndexStart); CreateTLASInstanceBuffer(); UploadTLASInstanceBuffer(); @@ -139,7 +140,7 @@ void VkLevelMesh::BeginFrame() .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT) .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); - UpdateTopLevelAS(); + UpdateTopLevelAS(DynamicBLAS.AccelStruct ? 2 : 1); // Finish building the accel struct before using it from the shaders PipelineBarrier() @@ -161,36 +162,6 @@ void VkLevelMesh::UploadMeshes(bool dynamicOnly) uploader.Upload(dynamicOnly); } -int VkLevelMesh::GetMaxVertexBufferSize() -{ - return Mesh->StaticMesh->Mesh.Vertices.Size() + MaxDynamicVertices; -} - -int VkLevelMesh::GetMaxIndexBufferSize() -{ - return Mesh->StaticMesh->Mesh.Indexes.Size() + MaxDynamicIndexes; -} - -int VkLevelMesh::GetMaxNodeBufferSize() -{ - return (int)Mesh->StaticMesh->Collision->get_nodes().size() + MaxDynamicNodes + 1; // + 1 for the merge root node -} - -int VkLevelMesh::GetMaxSurfaceBufferSize() -{ - return Mesh->StaticMesh->GetSurfaceCount() + MaxDynamicSurfaces; -} - -int VkLevelMesh::GetMaxUniformsBufferSize() -{ - return Mesh->StaticMesh->Mesh.Uniforms.Size() + MaxDynamicUniforms; -} - -int VkLevelMesh::GetMaxSurfaceIndexBufferSize() -{ - return Mesh->StaticMesh->Mesh.SurfaceIndexes.Size() + MaxDynamicSurfaceIndexes; -} - void VkLevelMesh::CreateBuffers() { VertexBuffer = BufferBuilder() @@ -201,7 +172,7 @@ void VkLevelMesh::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(GetMaxVertexBufferSize() * sizeof(FFlatVertex)) + .Size(Mesh->Mesh.MaxVertices * sizeof(FFlatVertex)) .DebugName("VertexBuffer") .Create(fb->GetDevice()); @@ -209,7 +180,7 @@ void VkLevelMesh::CreateBuffers() .Usage( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(GetMaxVertexBufferSize() * sizeof(int)) + .Size(Mesh->Mesh.MaxVertices * sizeof(int)) .DebugName("UniformIndexes") .Create(fb->GetDevice()); @@ -221,31 +192,31 @@ void VkLevelMesh::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)GetMaxIndexBufferSize() * sizeof(uint32_t)) + .Size((size_t)Mesh->Mesh.MaxIndexes * sizeof(uint32_t)) .DebugName("IndexBuffer") .Create(fb->GetDevice()); NodeBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(sizeof(CollisionNodeBufferHeader) + GetMaxNodeBufferSize() * sizeof(CollisionNode)) + .Size(sizeof(CollisionNodeBufferHeader) + Mesh->Mesh.MaxNodes * sizeof(CollisionNode)) .DebugName("NodeBuffer") .Create(fb->GetDevice()); SurfaceIndexBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(GetMaxSurfaceIndexBufferSize() * sizeof(int)) + .Size(Mesh->Mesh.MaxSurfaceIndexes * sizeof(int)) .DebugName("SurfaceBuffer") .Create(fb->GetDevice()); SurfaceBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(GetMaxSurfaceBufferSize() * sizeof(SurfaceInfo)) + .Size(Mesh->Mesh.MaxSurfaces * sizeof(SurfaceInfo)) .DebugName("SurfaceBuffer") .Create(fb->GetDevice()); UniformsBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(GetMaxUniformsBufferSize() * sizeof(SurfaceUniforms)) + .Size(Mesh->Mesh.MaxUniforms * sizeof(SurfaceUniforms)) .DebugName("SurfaceUniformsBuffer") .Create(fb->GetDevice()); @@ -256,7 +227,7 @@ void VkLevelMesh::CreateBuffers() .Create(fb->GetDevice()); } -VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFastBuild, int vertexOffset, int indexOffset) +VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(bool preferFastBuild, int indexOffset, int indexCount) { BLAS blas; @@ -272,7 +243,7 @@ VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFast accelStructBLDesc.geometry.triangles.vertexStride = sizeof(FFlatVertex); accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; accelStructBLDesc.geometry.triangles.indexData.deviceAddress = IndexBuffer->GetDeviceAddress() + indexOffset * sizeof(uint32_t); - accelStructBLDesc.geometry.triangles.maxVertex = vertexOffset + submesh->Mesh.Vertices.Size() - 1; + accelStructBLDesc.geometry.triangles.maxVertex = Mesh->Mesh.Vertices.Size() - 1; buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; buildInfo.flags = preferFastBuild ? VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR : VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; @@ -280,7 +251,7 @@ VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFast buildInfo.geometryCount = 1; buildInfo.ppGeometries = geometries; - uint32_t maxPrimitiveCount = submesh->Mesh.Indexes.Size() / 3; + uint32_t maxPrimitiveCount = indexCount / 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); @@ -318,12 +289,13 @@ VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFast void VkLevelMesh::CreateStaticBLAS() { - StaticBLAS = CreateBLAS(Mesh->StaticMesh.get(), false, 0, 0); + StaticBLAS = CreateBLAS(false, 0, Mesh->Mesh.DynamicIndexStart); } void VkLevelMesh::CreateDynamicBLAS() { - DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Indexes.Size()); + if (Mesh->Mesh.DynamicIndexStart < (int)Mesh->Mesh.Indexes.Size()) + DynamicBLAS = CreateBLAS(true, Mesh->Mesh.DynamicIndexStart, Mesh->Mesh.Indexes.Size() - Mesh->Mesh.DynamicIndexStart); } void VkLevelMesh::CreateTLASInstanceBuffer() @@ -341,7 +313,7 @@ void VkLevelMesh::CreateTLASInstanceBuffer() .Create(fb->GetDevice()); } -void VkLevelMesh::CreateTopLevelAS() +void VkLevelMesh::CreateTopLevelAS(int instanceCount) { VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; @@ -386,12 +358,12 @@ void VkLevelMesh::CreateTopLevelAS() VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; - rangeInfo.primitiveCount = 2; + rangeInfo.primitiveCount = instanceCount; fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos); } -void VkLevelMesh::UpdateTopLevelAS() +void VkLevelMesh::UpdateTopLevelAS(int instanceCount) { VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; @@ -412,7 +384,7 @@ void VkLevelMesh::UpdateTopLevelAS() VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; - rangeInfo.primitiveCount = 2; + rangeInfo.primitiveCount = instanceCount; fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos); } @@ -427,12 +399,15 @@ void VkLevelMesh::UploadTLASInstanceBuffer() instances[0].flags = 0; instances[0].accelerationStructureReference = StaticBLAS.AccelStruct->GetDeviceAddress(); - instances[1].transform.matrix[0][0] = 1.0f; - instances[1].transform.matrix[1][1] = 1.0f; - instances[1].transform.matrix[2][2] = 1.0f; - instances[1].mask = 0xff; - instances[1].flags = 0; - instances[1].accelerationStructureReference = DynamicBLAS.AccelStruct->GetDeviceAddress(); + if (DynamicBLAS.AccelStruct) + { + instances[1].transform.matrix[0][0] = 1.0f; + instances[1].transform.matrix[1][1] = 1.0f; + instances[1].transform.matrix[2][2] = 1.0f; + instances[1].mask = 0xff; + instances[1].flags = 0; + instances[1].accelerationStructureReference = DynamicBLAS.AccelStruct->GetDeviceAddress(); + } auto data = (uint8_t*)TopLevelAS.TransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR) * 2); memcpy(data, instances, sizeof(VkAccelerationStructureInstanceKHR) * 2); @@ -450,7 +425,6 @@ VkLevelMeshUploader::VkLevelMeshUploader(VkLevelMesh* mesh) : Mesh(mesh) void VkLevelMeshUploader::Upload(bool dynamicOnly) { UpdateSizes(); - UpdateLocations(); start = dynamicOnly; end = locations.Size(); @@ -501,6 +475,7 @@ static FVector3 SwapYZ(const FVector3& v) void VkLevelMeshUploader::UploadNodes() { +#if 0 // Copy node buffer header and create a root node that merges the static and dynamic AABB trees if (locations[1].Submesh->Collision->get_root() != -1) { @@ -530,9 +505,10 @@ void VkLevelMeshUploader::UploadNodes() cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos + sizeof(CollisionNodeBufferHeader), sizeof(CollisionNodeBufferHeader) + nodesHeader.root * sizeof(CollisionNode), sizeof(CollisionNode)); } else // second submesh is empty, just point the header at the first one +#endif { CollisionNodeBufferHeader nodesHeader; - nodesHeader.root = locations[0].Submesh->Collision->get_root(); + nodesHeader.root = Mesh->Mesh->Collision->get_root(); *((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader; cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader)); @@ -543,10 +519,9 @@ void VkLevelMeshUploader::UploadNodes() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; CollisionNode* nodes = (CollisionNode*)(data + datapos); - for (auto& node : submesh->Collision->get_nodes()) + for (auto& node : Mesh->Mesh->Collision->get_nodes()) { CollisionNode info; info.center = SwapYZ(node.aabb.Center); @@ -557,7 +532,7 @@ void VkLevelMeshUploader::UploadNodes() *(nodes++) = info; } - size_t copysize = submesh->Collision->get_nodes().size() * sizeof(CollisionNode); + size_t copysize = Mesh->Mesh->Collision->get_nodes().size() * sizeof(CollisionNode); if (copysize > 0) cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, sizeof(CollisionNodeBufferHeader) + cur.Node.Offset * sizeof(CollisionNode), copysize); datapos += copysize; @@ -569,10 +544,9 @@ void VkLevelMeshUploader::UploadVertices() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - size_t copysize = submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); - memcpy(data + datapos, submesh->Mesh.Vertices.Data(), copysize); + size_t copysize = Mesh->Mesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); + memcpy(data + datapos, Mesh->Mesh->Mesh.Vertices.Data(), copysize); if (copysize > 0) cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->VertexBuffer.get(), datapos, cur.Vertex.Offset * sizeof(FFlatVertex), copysize); datapos += copysize; @@ -584,10 +558,9 @@ void VkLevelMeshUploader::UploadUniformIndexes() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - size_t copysize = submesh->Mesh.UniformIndexes.Size() * sizeof(int); - memcpy(data + datapos, submesh->Mesh.UniformIndexes.Data(), copysize); + size_t copysize = Mesh->Mesh->Mesh.UniformIndexes.Size() * sizeof(int); + memcpy(data + datapos, Mesh->Mesh->Mesh.UniformIndexes.Data(), copysize); if (copysize > 0) cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->UniformIndexBuffer.get(), datapos, cur.UniformIndexes.Offset * sizeof(int), copysize); datapos += copysize; @@ -599,13 +572,12 @@ void VkLevelMeshUploader::UploadIndexes() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; uint32_t* indexes = (uint32_t*)(data + datapos); - for (int j = 0, count = submesh->Mesh.Indexes.Size(); j < count; ++j) - *(indexes++) = cur.Vertex.Offset + submesh->Mesh.Indexes[j]; + for (int j = 0, count = Mesh->Mesh->Mesh.Indexes.Size(); j < count; ++j) + *(indexes++) = cur.Vertex.Offset + Mesh->Mesh->Mesh.Indexes[j]; - size_t copysize = submesh->Mesh.Indexes.Size() * sizeof(uint32_t); + size_t copysize = Mesh->Mesh->Mesh.Indexes.Size() * sizeof(uint32_t); if (copysize > 0) cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->IndexBuffer.get(), datapos, cur.Index.Offset * sizeof(uint32_t), copysize); datapos += copysize; @@ -617,13 +589,12 @@ void VkLevelMeshUploader::UploadSurfaceIndexes() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; int* indexes = (int*)(data + datapos); - for (int j = 0, count = submesh->Mesh.SurfaceIndexes.Size(); j < count; ++j) - *(indexes++) = cur.SurfaceIndex.Offset + submesh->Mesh.SurfaceIndexes[j]; + for (int j = 0, count = Mesh->Mesh->Mesh.SurfaceIndexes.Size(); j < count; ++j) + *(indexes++) = cur.SurfaceIndex.Offset + Mesh->Mesh->Mesh.SurfaceIndexes[j]; - size_t copysize = submesh->Mesh.SurfaceIndexes.Size() * sizeof(int); + size_t copysize = Mesh->Mesh->Mesh.SurfaceIndexes.Size() * sizeof(int); if (copysize > 0) cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->SurfaceIndexBuffer.get(), datapos, cur.SurfaceIndex.Offset * sizeof(int), copysize); datapos += copysize; @@ -635,12 +606,11 @@ void VkLevelMeshUploader::UploadSurfaces() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos); - for (int j = 0, count = submesh->GetSurfaceCount(); j < count; ++j) + for (int j = 0, count = Mesh->Mesh->GetSurfaceCount(); j < count; ++j) { - LevelMeshSurface* surface = submesh->GetSurface(j); + LevelMeshSurface* surface = Mesh->Mesh->GetSurface(j); SurfaceInfo info; info.Normal = FVector3(surface->Plane.X, surface->Plane.Z, surface->Plane.Y); @@ -660,7 +630,7 @@ void VkLevelMeshUploader::UploadSurfaces() *(surfaces++) = info; } - size_t copysize = submesh->GetSurfaceCount() * sizeof(SurfaceInfo); + size_t copysize = Mesh->Mesh->GetSurfaceCount() * sizeof(SurfaceInfo); if (copysize > 0) cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->SurfaceBuffer.get(), datapos, cur.Surface.Offset * sizeof(SurfaceInfo), copysize); datapos += copysize; @@ -672,12 +642,11 @@ void VkLevelMeshUploader::UploadUniforms() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - for (int j = 0, count = submesh->Mesh.Uniforms.Size(); j < count; j++) + for (int j = 0, count = Mesh->Mesh->Mesh.Uniforms.Size(); j < count; j++) { - auto& surfaceUniforms = submesh->Mesh.Uniforms[j]; - auto& material = submesh->Mesh.Materials[j]; + auto& surfaceUniforms = Mesh->Mesh->Mesh.Uniforms[j]; + auto& material = Mesh->Mesh->Mesh.Materials[j]; if (material.mMaterial) { auto source = material.mMaterial->Source(); @@ -691,8 +660,8 @@ void VkLevelMeshUploader::UploadUniforms() } SurfaceUniforms* uniforms = (SurfaceUniforms*)(data + datapos); - size_t copysize = submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); - memcpy(uniforms, submesh->Mesh.Uniforms.Data(), copysize); + size_t copysize = Mesh->Mesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); + memcpy(uniforms, Mesh->Mesh->Mesh.Uniforms.Data(), copysize); if (copysize > 0) cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->UniformsBuffer.get(), datapos, cur.Uniforms.Offset * sizeof(SurfaceUniforms), copysize); datapos += copysize; @@ -720,47 +689,15 @@ void VkLevelMeshUploader::UploadPortals() void VkLevelMeshUploader::UpdateSizes() { - for (LevelSubmesh* submesh : { Mesh->GetMesh()->StaticMesh.get(), Mesh->GetMesh()->DynamicMesh.get() }) - { - SubmeshBufferLocation location; - location.Submesh = submesh; - location.Vertex.Size = submesh->Mesh.Vertices.Size(); - location.Index.Size = submesh->Mesh.Indexes.Size(); - location.Node.Size = (int)submesh->Collision->get_nodes().size(); - location.SurfaceIndex.Size = submesh->Mesh.SurfaceIndexes.Size(); - location.Surface.Size = submesh->GetSurfaceCount(); - location.UniformIndexes.Size = submesh->Mesh.UniformIndexes.Size(); - location.Uniforms.Size = submesh->Mesh.Uniforms.Size(); - locations.Push(location); - } -} - -void VkLevelMeshUploader::UpdateLocations() -{ - for (unsigned int i = 1, count = locations.Size(); i < count; i++) - { - const SubmeshBufferLocation& prev = locations[i - 1]; - SubmeshBufferLocation& cur = locations[i]; - cur.Vertex.Offset = prev.Vertex.Offset + prev.Vertex.Size; - cur.Index.Offset = prev.Index.Offset + prev.Index.Size; - cur.Node.Offset = prev.Node.Offset + prev.Node.Size; - cur.SurfaceIndex.Offset = prev.SurfaceIndex.Offset + prev.SurfaceIndex.Size; - cur.Surface.Offset = prev.Surface.Offset + prev.Surface.Size; - cur.UniformIndexes.Offset = prev.UniformIndexes.Offset + prev.UniformIndexes.Size; - cur.Uniforms.Offset = prev.Uniforms.Offset + prev.Uniforms.Size; - - if ( - cur.Vertex.Offset + cur.Vertex.Size > Mesh->GetMaxVertexBufferSize() || - cur.Index.Offset + cur.Index.Size > Mesh->GetMaxIndexBufferSize() || - cur.Node.Offset + cur.Node.Size > Mesh->GetMaxNodeBufferSize() || - cur.SurfaceIndex.Offset + cur.SurfaceIndex.Size > Mesh->GetMaxSurfaceIndexBufferSize() || - cur.Surface.Offset + cur.Surface.Size > Mesh->GetMaxSurfaceBufferSize() || - cur.UniformIndexes.Offset + cur.UniformIndexes.Size > Mesh->GetMaxVertexBufferSize() || - cur.Uniforms.Offset + cur.Uniforms.Size > Mesh->GetMaxUniformsBufferSize()) - { - I_FatalError("Dynamic accel struct buffers are too small!"); - } - } + SubmeshBufferLocation location; + location.Vertex.Size = Mesh->Mesh->Mesh.Vertices.Size(); + location.Index.Size = Mesh->Mesh->Mesh.Indexes.Size(); + location.Node.Size = (int)Mesh->Mesh->Collision->get_nodes().size(); + location.SurfaceIndex.Size = Mesh->Mesh->Mesh.SurfaceIndexes.Size(); + location.Surface.Size = Mesh->Mesh->GetSurfaceCount(); + location.UniformIndexes.Size = Mesh->Mesh->Mesh.UniformIndexes.Size(); + location.Uniforms.Size = Mesh->Mesh->Mesh.Uniforms.Size(); + locations.Push(location); } size_t VkLevelMeshUploader::GetTransferSize() @@ -770,13 +707,13 @@ size_t VkLevelMeshUploader::GetTransferSize() for (unsigned int i = start; i < end; i++) { const SubmeshBufferLocation& cur = locations[i]; - transferBufferSize += cur.Submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); - transferBufferSize += cur.Submesh->Mesh.UniformIndexes.Size() * sizeof(int); - transferBufferSize += cur.Submesh->Mesh.Indexes.Size() * sizeof(uint32_t); - transferBufferSize += cur.Submesh->Collision->get_nodes().size() * sizeof(CollisionNode); - transferBufferSize += cur.Submesh->Mesh.SurfaceIndexes.Size() * sizeof(int); - transferBufferSize += cur.Submesh->GetSurfaceCount() * sizeof(SurfaceInfo); - transferBufferSize += cur.Submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); + transferBufferSize += Mesh->Mesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); + transferBufferSize += Mesh->Mesh->Mesh.UniformIndexes.Size() * sizeof(int); + transferBufferSize += Mesh->Mesh->Mesh.Indexes.Size() * sizeof(uint32_t); + transferBufferSize += Mesh->Mesh->Collision->get_nodes().size() * sizeof(CollisionNode); + transferBufferSize += Mesh->Mesh->Mesh.SurfaceIndexes.Size() * sizeof(int); + transferBufferSize += Mesh->Mesh->GetSurfaceCount() * sizeof(SurfaceInfo); + transferBufferSize += Mesh->Mesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); } if (start == 0) transferBufferSize += Mesh->GetMesh()->Portals.Size() * sizeof(PortalInfo); diff --git a/src/common/rendering/vulkan/vk_levelmesh.h b/src/common/rendering/vulkan/vk_levelmesh.h index 724aa6a2f..3532919d1 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.h +++ b/src/common/rendering/vulkan/vk_levelmesh.h @@ -50,7 +50,6 @@ struct SubmeshBufferRange struct SubmeshBufferLocation { - LevelSubmesh* Submesh = nullptr; SubmeshBufferRange Vertex; SubmeshBufferRange Index; SubmeshBufferRange Node; @@ -94,20 +93,13 @@ private: void CreateStaticBLAS(); void CreateDynamicBLAS(); void CreateTLASInstanceBuffer(); - void CreateTopLevelAS(); + void CreateTopLevelAS(int instanceCount); void UploadMeshes(bool dynamicOnly); void UploadTLASInstanceBuffer(); - void UpdateTopLevelAS(); + void UpdateTopLevelAS(int instanceCount); - BLAS CreateBLAS(LevelSubmesh *submesh, bool preferFastBuild, int vertexOffset, int indexOffset); - - int GetMaxVertexBufferSize(); - int GetMaxIndexBufferSize(); - int GetMaxNodeBufferSize(); - int GetMaxSurfaceBufferSize(); - int GetMaxUniformsBufferSize(); - int GetMaxSurfaceIndexBufferSize(); + BLAS CreateBLAS(bool preferFastBuild, int indexOffset, int indexCount); VulkanRenderDevice* fb = nullptr; @@ -168,7 +160,6 @@ private: void UploadUniforms(); void UploadPortals(); void UpdateSizes(); - void UpdateLocations(); size_t GetTransferSize(); VkLevelMesh* Mesh; diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index 085320c2d..699c5efe6 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -180,10 +180,6 @@ void VkLightmapper::Render() viewport.height = (float)bakeImageSize; cmdbuffer->setViewport(0, 1, &viewport); - int dynamicSurfaceIndexOffset = mesh->StaticMesh->GetSurfaceCount(); - int dynamicFirstIndexOffset = mesh->StaticMesh->Mesh.Indexes.Size(); - LevelSubmesh* staticMesh = mesh->StaticMesh.get(); - for (int i = 0, count = selectedTiles.Size(); i < count; i++) { auto& selectedTile = selectedTiles[i]; @@ -202,17 +198,10 @@ void VkLightmapper::Render() bool buffersFull = false; // Paint all surfaces visible in the tile - for (LevelMeshSurface* surface : targetTile->Surfaces) + for (int surfaceIndex : targetTile->Surfaces) { - int surfaceIndexOffset = 0; - int firstIndexOffset = 0; - if (surface->Submesh != staticMesh) - { - surfaceIndexOffset = dynamicSurfaceIndexOffset; - firstIndexOffset = dynamicFirstIndexOffset; - } - - pc.SurfaceIndex = surfaceIndexOffset + surface->Submesh->GetSurfaceIndex(surface); + LevelMeshSurface* surface = mesh->GetSurface(surfaceIndex); + pc.SurfaceIndex = surfaceIndex; if (surface->LightList.ResetCounter != lights.ResetCounter) { @@ -254,7 +243,7 @@ void VkLightmapper::Render() VkDrawIndexedIndirectCommand cmd; cmd.indexCount = surface->MeshLocation.NumElements; cmd.instanceCount = 1; - cmd.firstIndex = firstIndexOffset + surface->MeshLocation.StartElementIndex; + cmd.firstIndex = surface->MeshLocation.StartElementIndex; cmd.vertexOffset = 0; cmd.firstInstance = drawindexed.Pos; drawindexed.Constants[drawindexed.Pos] = pc; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index 7fc160a68..f0b2a38e0 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -483,9 +483,9 @@ void VulkanRenderDevice::BeginFrame() levelMeshChanged = false; mLevelMesh->SetLevelMesh(levelMesh); - if (levelMesh && levelMesh->StaticMesh->LMTextureCount > 0) + if (levelMesh && levelMesh->LMTextureCount > 0) { - GetTextureManager()->CreateLightmap(levelMesh->StaticMesh->LMTextureSize, levelMesh->StaticMesh->LMTextureCount, std::move(levelMesh->StaticMesh->LMTextureData)); + GetTextureManager()->CreateLightmap(levelMesh->LMTextureSize, levelMesh->LMTextureCount, std::move(levelMesh->LMTextureData)); GetLightmapper()->SetLevelMesh(levelMesh); } } diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index 40186cb37..3debce31f 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -856,12 +856,9 @@ void VkRenderState::DrawLevelMeshSurfaces(bool noFragmentShader) ApplyLevelMesh(); auto mesh = fb->GetLevelMesh()->GetMesh(); - for (LevelSubmesh* submesh : { mesh->StaticMesh.get(), mesh->DynamicMesh.get() }) + for (LevelSubmeshDrawRange& range : mesh->DrawList) { - for (LevelSubmeshDrawRange& range : submesh->DrawList) - { - DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, noFragmentShader); - } + DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, noFragmentShader); } } @@ -870,12 +867,9 @@ void VkRenderState::DrawLevelMeshPortals(bool noFragmentShader) ApplyLevelMesh(); auto mesh = fb->GetLevelMesh()->GetMesh(); - for (LevelSubmesh* submesh : { mesh->StaticMesh.get(), mesh->DynamicMesh.get() }) + for (LevelSubmeshDrawRange& range : mesh->PortalList) { - for (LevelSubmeshDrawRange& range : submesh->PortalList) - { - DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, noFragmentShader); - } + DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, noFragmentShader); } } diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index 0cdb28a7d..859d1b854 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3017,8 +3017,8 @@ void MapLoader::InitLevelMesh(MapData* map) { if (Level->lightmaps) { - Level->levelMesh->StaticMesh->SetupTileTransforms(); - Level->levelMesh->StaticMesh->PackLightmapAtlas(0); + Level->levelMesh->SetupTileTransforms(); + Level->levelMesh->PackLightmapAtlas(0); } } } @@ -3100,12 +3100,11 @@ bool MapLoader::LoadLightmap(MapData* map) uint8_t* data = (uint8_t*)&textureData[0]; fr.Read(data, numTexPixels * 3 * sizeof(uint16_t)); - auto submesh = Level->levelMesh->StaticMesh.get(); - const auto textureSize = submesh->LMTextureSize; + const auto textureSize = Level->levelMesh->LMTextureSize; // Create lookup for finding tiles std::map levelTiles; - for (LightmapTile& tile : submesh->LightmapTiles) + for (LightmapTile& tile : Level->levelMesh->LightmapTiles) { levelTiles[tile.Binding] = &tile; } @@ -3154,18 +3153,18 @@ bool MapLoader::LoadLightmap(MapData* map) } // 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) + for (auto& tile : Level->levelMesh->LightmapTiles) { if (tile.NeedsUpdate) - tile.SetupTileTransform(submesh->LMTextureSize); + tile.SetupTileTransform(Level->levelMesh->LMTextureSize); } // Place all tiles in atlas textures - submesh->PackLightmapAtlas(0); + Level->levelMesh->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)); + Level->levelMesh->LMTextureData.Resize(Level->levelMesh->LMTextureCount * textureSize * textureSize * 3); + memset(Level->levelMesh->LMTextureData.Data(), 0, Level->levelMesh->LMTextureData.Size() * sizeof(uint16_t)); // Copy tile pixels to the texture for (auto& binding : foundBindings) @@ -3174,7 +3173,7 @@ bool MapLoader::LoadLightmap(MapData* map) LightmapTile* tile = binding.second; const uint16_t* src = textureData.Data() + entry->pixelsOffset; - uint16_t* dst = &submesh->LMTextureData[tile->AtlasLocation.ArrayIndex * textureSize * textureSize * 3]; + uint16_t* dst = &Level->levelMesh->LMTextureData[tile->AtlasLocation.ArrayIndex * textureSize * textureSize * 3]; int destx = tile->AtlasLocation.X; int desty = tile->AtlasLocation.Y; int width = tile->AtlasLocation.Width; diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index f03c2ec72..ef9e2510e 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -1,7 +1,6 @@ #include "templates.h" #include "doom_levelmesh.h" -#include "doom_levelsubmesh.h" #include "g_levellocals.h" #include "texturemanager.h" #include "playsim/p_lnspec.h" @@ -9,6 +8,13 @@ #include "g_levellocals.h" #include "a_dynlight.h" #include "hw_renderstate.h" +#include "hw_vertexbuilder.h" +#include "hwrenderer/scene/hw_drawstructs.h" +#include "hwrenderer/scene/hw_drawinfo.h" +#include "hwrenderer/scene/hw_walldispatcher.h" +#include "hwrenderer/scene/hw_flatdispatcher.h" +#include "common/rendering/hwrenderer/data/hw_meshbuilder.h" +#include static bool RequireLevelMesh() { @@ -42,7 +48,7 @@ ADD_STAT(lightmap) return out; } - uint32_t atlasPixelCount = levelMesh->StaticMesh->AtlasPixelCount(); + uint32_t atlasPixelCount = levelMesh->AtlasPixelCount(); auto stats = levelMesh->GatherTilePixelStats(); out.Format("Surfaces: %u (awaiting updates: %u)\nSurface pixel area to update: %u\nSurface pixel area: %u\nAtlas pixel area: %u\nAtlas efficiency: %.4f%%", @@ -67,13 +73,13 @@ CCMD(invalidatelightmap) if (!RequireLightmap()) return; int count = 0; - for (auto& tile : level.levelMesh->StaticMesh->LightmapTiles) + for (auto& tile : level.levelMesh->LightmapTiles) { if (!tile.NeedsUpdate) ++count; tile.NeedsUpdate = true; } - Printf("Marked %d out of %d tiles for update.\n", count, level.levelMesh->StaticMesh->LightmapTiles.Size()); + Printf("Marked %d out of %d tiles for update.\n", count, level.levelMesh->LightmapTiles.Size()); } void PrintSurfaceInfo(const DoomLevelMeshSurface* surface) @@ -82,10 +88,10 @@ void PrintSurfaceInfo(const DoomLevelMeshSurface* surface) auto gameTexture = surface->Texture; - Printf("Surface %d (%p)\n Type: %d, TypeIndex: %d, ControlSector: %d\n", surface->Submesh->GetSurfaceIndex(surface), surface, surface->Type, surface->TypeIndex, surface->ControlSector ? surface->ControlSector->Index() : -1); + Printf("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); if (surface->LightmapTileIndex >= 0) { - LightmapTile* tile = &surface->Submesh->LightmapTiles[surface->LightmapTileIndex]; + LightmapTile* tile = &level.levelMesh->LightmapTiles[surface->LightmapTileIndex]; Printf(" Atlas page: %d, x:%d, y:%d\n", tile->AtlasLocation.ArrayIndex, tile->AtlasLocation.X, tile->AtlasLocation.Y); Printf(" Pixels: %dx%d (area: %d)\n", tile->AtlasLocation.Width, tile->AtlasLocation.Height, tile->AtlasLocation.Area()); Printf(" Sample dimension: %d\n", tile->SampleDimension); @@ -142,24 +148,46 @@ EXTERN_CVAR(Float, lm_scale); DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap) { + // Remove the empty mesh added in the LevelMesh constructor + Mesh.Vertices.clear(); + Mesh.Indexes.clear(); + SunColor = doomMap.SunColor; // TODO keep only one copy? SunDirection = doomMap.SunDirection; BuildSectorGroups(doomMap); CreatePortals(doomMap); - StaticMesh = std::make_unique(this, doomMap, true); - DynamicMesh = std::make_unique(this, doomMap, false); + LightmapSampleDistance = doomMap.LightmapSampleDistance; + + CreateSurfaces(doomMap); + LinkSurfaces(doomMap); + + SortIndexes(); + BuildTileSurfaceLists(); + + Mesh.DynamicIndexStart = Mesh.Indexes.size(); + UpdateCollision(); + + // Assume double the size of the static mesh will be enough for anything dynamic. + Mesh.MaxVertices = std::max(Mesh.Vertices.size() * 2, (size_t)10000); + Mesh.MaxIndexes = std::max(Mesh.Indexes.size() * 2, (size_t)10000); + Mesh.MaxSurfaces = std::max(Mesh.SurfaceIndexes.size() * 2, (size_t)10000); + Mesh.MaxUniforms = std::max(Mesh.Uniforms.size() * 2, (size_t)10000); + Mesh.MaxSurfaceIndexes = std::max(Mesh.SurfaceIndexes.size() * 2, (size_t)10000); + Mesh.MaxNodes = std::max(Collision->get_nodes().size() * 2, (size_t)10000); } void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap) { +#if 0 static_cast(DynamicMesh.get())->Update(doomMap); if (doomMap.lightmaps) { DynamicMesh->SetupTileTransforms(); DynamicMesh->PackLightmapAtlas(StaticMesh->LMTextureCount); } +#endif } bool DoomLevelMesh::TraceSky(const FVector3& start, FVector3 direction, float dist) @@ -252,24 +280,585 @@ FLightNode* DoomLevelMesh::GetSurfaceLightNode(const DoomLevelMeshSurface* dooms return node; } +void DoomLevelMesh::CreateSurfaces(FLevelLocals& doomMap) +{ + // We can't use side->segs since it is null. + TArray> sideSegs(doomMap.sides.Size(), true); + for (unsigned int i = 0; i < doomMap.subsectors.Size(); i++) + { + subsector_t* sub = &doomMap.subsectors[i]; + sector_t* sector = sub->sector; + for (int i = 0, count = sub->numlines; i < count; i++) + { + seg_t* seg = sub->firstline + i; + if (seg->sidedef) + sideSegs[seg->sidedef->Index()] = { sub, seg }; + } + } + + MeshBuilder state; + std::map bindings; + + // Create surface objects for all sides + for (unsigned int i = 0; i < doomMap.sides.Size(); i++) + { + side_t* side = &doomMap.sides[i]; + bool isPolyLine = !!(side->Flags & WALLF_POLYOBJ); + if (isPolyLine) + continue; + + subsector_t* sub = sideSegs[i].first; + seg_t* seg = sideSegs[i].second; + if (!seg) + continue; + + sector_t* front = side->sector; + sector_t* back = (side->linedef->frontsector == front) ? side->linedef->backsector : side->linedef->frontsector; + + HWMeshHelper result; + HWWallDispatcher disp(&doomMap, &result, getRealLightmode(&doomMap, true)); + HWWall wall; + wall.sub = sub; + wall.Process(&disp, state, seg, front, back); + + // Part 1: solid geometry. This is set up so that there are no transparent parts + state.SetDepthFunc(DF_LEqual); + state.ClearDepthBias(); + state.EnableTexture(true); + state.EnableBrightmap(true); + state.AlphaFunc(Alpha_GEqual, 0.f); + CreateWallSurface(side, disp, state, bindings, result.list, false, true); + + for (HWWall& portal : result.portals) + { + WallPortals.Push(portal); + } + + CreateWallSurface(side, disp, state, bindings, result.portals, true, false); + + /* + // final pass: translucent stuff + state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); + state.SetRenderStyle(STYLE_Translucent); + CreateWallSurface(side, disp, state, bindings, result.translucent, false, true); + state.AlphaFunc(Alpha_GEqual, 0.f); + state.SetRenderStyle(STYLE_Normal); + */ + } + + // Create surfaces for all flats + for (unsigned int i = 0; i < doomMap.sectors.Size(); i++) + { + sector_t* sector = &doomMap.sectors[i]; + if (sector->subsectors[0]->flags & SSECF_POLYORG) + continue; + for (FSection& section : doomMap.sections.SectionsForSector(i)) + { + int sectionIndex = doomMap.sections.SectionIndex(§ion); + + HWFlatMeshHelper result; + HWFlatDispatcher disp(&doomMap, &result, getRealLightmode(&doomMap, true)); + + HWFlat flat; + flat.section = §ion; + flat.ProcessSector(&disp, state, sector); + + // Part 1: solid geometry. This is set up so that there are no transparent parts + state.SetDepthFunc(DF_LEqual); + state.ClearDepthBias(); + state.EnableTexture(true); + state.EnableBrightmap(true); + CreateFlatSurface(disp, state, bindings, result.list); + + CreateFlatSurface(disp, state, bindings, result.portals, true); + + // final pass: translucent stuff + state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); + state.SetRenderStyle(STYLE_Translucent); + CreateFlatSurface(disp, state, bindings, result.translucentborder); + state.SetDepthMask(false); + CreateFlatSurface(disp, state, bindings, result.translucent); + state.AlphaFunc(Alpha_GEqual, 0.f); + state.SetDepthMask(true); + state.SetRenderStyle(STYLE_Normal); + } + } +} + +void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky, bool translucent) +{ + for (HWWall& wallpart : list) + { + if (isSky) + { + state.SetEffect(EFF_PORTAL); + state.EnableTexture(false); + state.SetRenderStyle(STYLE_Normal); + + wallpart.MakeVertices(state, false); + wallpart.RenderWall(state, HWWall::RWF_BLANK); + wallpart.vertcount = 0; + + wallpart.LevelMeshInfo.Type = ST_NONE; + wallpart.LevelMeshInfo.ControlSector = nullptr; + + state.SetEffect(EFF_NONE); + state.EnableTexture(true); + } + else + { + if (wallpart.texture && wallpart.texture->isMasked()) + { + state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + } + else + { + state.AlphaFunc(Alpha_GEqual, 0.f); + } + + wallpart.DrawWall(&disp, state, translucent); + } + + int pipelineID = 0; + int startVertIndex = Mesh.Vertices.Size(); + int startElementIndex = Mesh.Indexes.Size(); + for (auto& it : state.mSortedLists) + { + const MeshApplyState& applyState = it.first; + + pipelineID = screen->GetLevelMeshPipelineID(applyState.applyData, applyState.surfaceUniforms, applyState.material); + + int uniformsIndex = Mesh.Uniforms.Size(); + Mesh.Uniforms.Push(applyState.surfaceUniforms); + Mesh.Materials.Push(applyState.material); + + for (MeshDrawCommand& command : it.second.mDraws) + { + for (int i = command.Start, end = command.Start + command.Count; i < end; i++) + { + Mesh.Vertices.Push(state.mVertices[i]); + Mesh.UniformIndexes.Push(uniformsIndex); + } + + if (command.DrawType == DT_TriangleFan) + { + for (int i = 2, count = command.Count; i < count; i++) + { + Mesh.Indexes.Push(startVertIndex); + Mesh.Indexes.Push(startVertIndex + i - 1); + Mesh.Indexes.Push(startVertIndex + i); + } + } + } + } + state.mSortedLists.clear(); + state.mVertices.Clear(); + state.mIndexes.Clear(); + + FVector2 v1 = FVector2(side->V1()->fPos()); + FVector2 v2 = FVector2(side->V2()->fPos()); + FVector2 N = FVector2(v2.Y - v1.Y, v1.X - v2.X).Unit(); + + DoomLevelMeshSurface surf; + surf.Type = wallpart.LevelMeshInfo.Type; + surf.ControlSector = wallpart.LevelMeshInfo.ControlSector; + surf.TypeIndex = side->Index(); + surf.Side = side; + surf.AlwaysUpdate = !!(side->sector->Flags & SECF_LM_DYNAMIC); + surf.SectorGroup = sectorGroup[side->sector->Index()]; + surf.Alpha = float(side->linedef->alpha); + surf.MeshLocation.StartVertIndex = startVertIndex; + surf.MeshLocation.StartElementIndex = startElementIndex; + surf.MeshLocation.NumVerts = Mesh.Vertices.Size() - startVertIndex; + surf.MeshLocation.NumElements = Mesh.Indexes.Size() - startElementIndex; + surf.Plane = FVector4(N.X, N.Y, 0.0f, v1 | N); + surf.Texture = wallpart.texture; + surf.PipelineID = pipelineID; + surf.PortalIndex = isSky ? linePortals[side->linedef->Index()] : 0; + surf.IsSky = isSky; + surf.Bounds = GetBoundsFromSurface(surf); + surf.LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(surf, bindings) : -1; + Surfaces.Push(surf); + } +} + +int DoomLevelMesh::AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map& bindings) +{ + if (surf.IsSky) + return -1; + + LightmapTileBinding binding; + binding.Type = surf.Type; + binding.TypeIndex = surf.TypeIndex; + binding.ControlSector = surf.ControlSector ? surf.ControlSector->Index() : (int)0xffffffffUL; + + auto it = bindings.find(binding); + if (it != bindings.end()) + { + int index = it->second; + + LightmapTile& tile = LightmapTiles[index]; + tile.Bounds.min.X = std::min(tile.Bounds.min.X, surf.Bounds.min.X); + tile.Bounds.min.Y = std::min(tile.Bounds.min.Y, surf.Bounds.min.Y); + tile.Bounds.min.Z = std::min(tile.Bounds.min.Z, surf.Bounds.min.Z); + tile.Bounds.max.X = std::max(tile.Bounds.max.X, surf.Bounds.max.X); + tile.Bounds.max.Y = std::max(tile.Bounds.max.Y, surf.Bounds.max.Y); + tile.Bounds.max.Z = std::max(tile.Bounds.max.Z, surf.Bounds.max.Z); + + return index; + } + else + { + int index = LightmapTiles.Size(); + + LightmapTile tile; + tile.Binding = binding; + tile.Bounds = surf.Bounds; + tile.Plane = surf.Plane; + tile.SampleDimension = GetSampleDimension(surf); + + LightmapTiles.Push(tile); + bindings[binding] = index; + return index; + } +} + +int DoomLevelMesh::GetSampleDimension(const DoomLevelMeshSurface& surf) +{ + uint16_t sampleDimension = 0; // To do: something seems to have gone missing with the sample dimension! + + if (sampleDimension <= 0) + { + sampleDimension = LightmapSampleDistance; + } + + sampleDimension = uint16_t(max(int(roundf(float(sampleDimension) / max(1.0f / 4, float(lm_scale)))), 1)); + + // Round to nearest power of two + uint32_t n = uint16_t(sampleDimension); + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n = (n + 1) >> 1; + sampleDimension = uint16_t(n) ? uint16_t(n) : uint16_t(0xFFFF); + + return sampleDimension; +} + +void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky) +{ + for (HWFlat& flatpart : list) + { + if (isSky) + { + state.SetEffect(EFF_PORTAL); + state.EnableTexture(false); + state.SetRenderStyle(STYLE_Normal); + + flatpart.DrawSubsectors(&disp, state); + + state.SetEffect(EFF_NONE); + state.EnableTexture(true); + } + else + { + if (flatpart.texture && flatpart.texture->isMasked()) + { + state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + } + else + { + state.AlphaFunc(Alpha_GEqual, 0.f); + } + + flatpart.DrawFlat(&disp, state, false); + } + + VSMatrix textureMatrix; + textureMatrix.loadIdentity(); + + int pipelineID = 0; + int uniformsIndex = 0; + bool foundDraw = false; + for (auto& it : state.mSortedLists) + { + const MeshApplyState& applyState = it.first; + + pipelineID = screen->GetLevelMeshPipelineID(applyState.applyData, applyState.surfaceUniforms, applyState.material); + uniformsIndex = Mesh.Uniforms.Size(); + textureMatrix = applyState.textureMatrix; + Mesh.Uniforms.Push(applyState.surfaceUniforms); + Mesh.Materials.Push(applyState.material); + + foundDraw = true; + break; + } + state.mSortedLists.clear(); + state.mVertices.Clear(); + state.mIndexes.Clear(); + + if (!foundDraw) + continue; + + DoomLevelMeshSurface surf; + surf.Type = flatpart.ceiling ? ST_CEILING : ST_FLOOR; + surf.ControlSector = flatpart.controlsector ? flatpart.controlsector->model : nullptr; + surf.AlwaysUpdate = !!(flatpart.sector->Flags & SECF_LM_DYNAMIC); + surf.SectorGroup = sectorGroup[flatpart.sector->Index()]; + surf.Alpha = flatpart.alpha; + surf.Texture = flatpart.texture; + surf.PipelineID = pipelineID; + surf.PortalIndex = sectorPortals[flatpart.ceiling][flatpart.sector->Index()]; + surf.IsSky = isSky; + + auto plane = surf.ControlSector ? surf.ControlSector->GetSecPlane(!flatpart.ceiling) : flatpart.sector->GetSecPlane(flatpart.ceiling); + surf.Plane = FVector4((float)plane.Normal().X, (float)plane.Normal().Y, (float)plane.Normal().Z, -(float)plane.D); + + if (surf.ControlSector) + surf.Plane = -surf.Plane; + + float skyZ = flatpart.ceiling ? 32768.0f : -32768.0f; + + for (subsector_t* sub : flatpart.section->subsectors) + { + if (sub->numlines < 3) + continue; + + int startVertIndex = Mesh.Vertices.Size(); + int startElementIndex = Mesh.Indexes.Size(); + + for (int i = 0, end = sub->numlines; i < end; i++) + { + auto& vt = sub->firstline[end - 1 - i].v1; + + FVector3 pt((float)vt->fX(), (float)vt->fY(), isSky ? skyZ : (float)plane.ZatPoint(vt)); + FVector4 uv = textureMatrix * FVector4(pt.X * (1.0f / 64.0f), pt.Y * (-1.0f / 64.0f), 0.0f, 1.0f); + + FFlatVertex ffv; + ffv.x = pt.X; + ffv.y = pt.Y; + ffv.z = pt.Z; + ffv.u = uv.X; + ffv.v = uv.Y; + ffv.lu = 0.0f; + ffv.lv = 0.0f; + ffv.lindex = -1.0f; + + Mesh.Vertices.Push(ffv); + Mesh.UniformIndexes.Push(uniformsIndex); + } + + if (flatpart.ceiling) + { + for (int i = 2, count = sub->numlines; i < count; i++) + { + Mesh.Indexes.Push(startVertIndex); + Mesh.Indexes.Push(startVertIndex + i - 1); + Mesh.Indexes.Push(startVertIndex + i); + } + } + else + { + for (int i = 2, count = sub->numlines; i < count; i++) + { + Mesh.Indexes.Push(startVertIndex + i); + Mesh.Indexes.Push(startVertIndex + i - 1); + Mesh.Indexes.Push(startVertIndex); + } + } + + surf.TypeIndex = sub->Index(); + surf.Subsector = sub; + surf.MeshLocation.StartVertIndex = startVertIndex; + surf.MeshLocation.StartElementIndex = startElementIndex; + surf.MeshLocation.NumVerts = sub->numlines; + surf.MeshLocation.NumElements = (sub->numlines - 2) * 3; + surf.Bounds = GetBoundsFromSurface(surf); + surf.LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(surf, bindings) : -1; + Surfaces.Push(surf); + } + } +} + +#if 0 +void DoomLevelMesh::CreateDynamicSurfaces(FLevelLocals& doomMap) +{ + // Look for polyobjects + for (unsigned int i = 0; i < doomMap.lines.Size(); i++) + { + side_t* side = doomMap.lines[i].sidedef[0]; + bool isPolyLine = !!(side->Flags & WALLF_POLYOBJ); + if (!isPolyLine) + continue; + + // Make sure we have a surface array on the polyobj sidedef + if (!side->surface) + { + auto array = std::make_unique(4); + memset(array.get(), 0, sizeof(DoomLevelMeshSurface*)); + side->surface = array.get(); + PolyLMSurfaces.Push(std::move(array)); + } + + CreateSideSurfaces(doomMap, side); + } +} +#endif + +void DoomLevelMesh::SortIndexes() +{ + // Order surfaces by pipeline + std::unordered_map> pipelineSurfaces; + for (size_t i = 0; i < Surfaces.Size(); i++) + { + DoomLevelMeshSurface* s = &Surfaces[i]; + pipelineSurfaces[(int64_t(s->PipelineID) << 32) | int64_t(s->IsSky)].Push(i); + } + + // Create reorder surface indexes by pipeline and create a draw range for each + TArray sortedIndexes; + for (const auto& it : pipelineSurfaces) + { + LevelSubmeshDrawRange range; + range.PipelineID = it.first >> 32; + range.Start = sortedIndexes.Size(); + + // Move indexes to new array + for (unsigned int i : it.second) + { + DoomLevelMeshSurface& s = Surfaces[i]; + + unsigned int start = s.MeshLocation.StartElementIndex; + unsigned int count = s.MeshLocation.NumElements; + + s.MeshLocation.StartElementIndex = sortedIndexes.Size(); + + for (unsigned int j = 0; j < count; j++) + { + sortedIndexes.Push(Mesh.Indexes[start + j]); + } + + for (unsigned int j = 0; j < count; j += 3) + { + Mesh.SurfaceIndexes.Push((int)i); + } + } + + range.Count = sortedIndexes.Size() - range.Start; + + if ((it.first & 1) == 0) + DrawList.Push(range); + else + PortalList.Push(range); + } + + Mesh.Indexes.Swap(sortedIndexes); +} + +void DoomLevelMesh::LinkSurfaces(FLevelLocals& doomMap) +{ + for (auto& surface : Surfaces) + { + if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING) + { + SetSubsectorLightmap(&surface); + } + else + { + SetSideLightmap(&surface); + } + } +} + +void DoomLevelMesh::SetSubsectorLightmap(DoomLevelMeshSurface* surface) +{ + if (surface->Subsector->firstline && surface->Subsector->firstline->sidedef) + surface->Subsector->firstline->sidedef->sector->HasLightmaps = true; + + if (!surface->ControlSector) + { + int index = surface->Type == ST_CEILING ? 1 : 0; + surface->Subsector->surface[index][0] = surface; + } + else + { + int index = surface->Type == ST_CEILING ? 0 : 1; + const auto& ffloors = surface->Subsector->sector->e->XFloor.ffloors; + for (unsigned int i = 0; i < ffloors.Size(); i++) + { + if (ffloors[i]->model == surface->ControlSector) + { + surface->Subsector->surface[index][i + 1] = surface; + } + } + } +} + +void DoomLevelMesh::SetSideLightmap(DoomLevelMeshSurface* surface) +{ + if (!surface->ControlSector) + { + if (surface->Type == ST_UPPERSIDE) + { + surface->Side->surface[0] = surface; + } + else if (surface->Type == ST_MIDDLESIDE) + { + surface->Side->surface[1] = surface; + surface->Side->surface[2] = surface; + } + else if (surface->Type == ST_LOWERSIDE) + { + surface->Side->surface[3] = surface; + } + } + else + { + const auto& ffloors = surface->Side->sector->e->XFloor.ffloors; + for (unsigned int i = 0; i < ffloors.Size(); i++) + { + if (ffloors[i]->model == surface->ControlSector) + { + surface->Side->surface[4 + i] = surface; + } + } + } +} + +BBox DoomLevelMesh::GetBoundsFromSurface(const LevelMeshSurface& surface) const +{ + BBox bounds; + bounds.Clear(); + for (int i = int(surface.MeshLocation.StartVertIndex); i < int(surface.MeshLocation.StartVertIndex) + surface.MeshLocation.NumVerts; i++) + { + FVector3 v = Mesh.Vertices[(int)i].fPos(); + bounds.min.X = std::min(bounds.min.X, v.X); + bounds.min.Y = std::min(bounds.min.Y, v.Y); + bounds.min.Z = std::min(bounds.min.Z, v.Z); + bounds.max.X = std::max(bounds.max.X, v.X); + bounds.max.Y = std::max(bounds.max.Y, v.Y); + bounds.max.Z = std::max(bounds.max.Z, v.Z); + } + return bounds; +} + void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilename) const { - DoomLevelSubmesh* submesh = static_cast(StaticMesh.get()); - auto f = fopen(objFilename.GetChars(), "w"); fprintf(f, "# DoomLevelMesh debug export\n"); - fprintf(f, "# Vertices: %u, Indexes: %u, Surfaces: %u\n", submesh->Mesh.Vertices.Size(), submesh->Mesh.Indexes.Size(), submesh->Surfaces.Size()); + fprintf(f, "# Vertices: %u, Indexes: %u, Surfaces: %u\n", Mesh.Vertices.Size(), Mesh.Indexes.Size(), Surfaces.Size()); fprintf(f, "mtllib %s\n", mtlFilename.GetChars()); double scale = 1 / 10.0; - for (const auto& v : submesh->Mesh.Vertices) + for (const auto& v : Mesh.Vertices) { fprintf(f, "v %f %f %f\n", v.x * scale, v.y * scale, v.z * scale); } - for (const auto& v : submesh->Mesh.Vertices) + for (const auto& v : Mesh.Vertices) { fprintf(f, "vt %f %f\n", v.lu, v.lv); } @@ -302,15 +891,15 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen bool useErrorMaterial = false; int highestUsedAtlasPage = -1; - for (unsigned i = 0, count = submesh->Mesh.Indexes.Size(); i + 2 < count; i += 3) + for (unsigned i = 0, count = Mesh.Indexes.Size(); i + 2 < count; i += 3) { - auto index = submesh->Mesh.SurfaceIndexes[i / 3]; + auto index = Mesh.SurfaceIndexes[i / 3]; if (index != lastSurfaceIndex) { lastSurfaceIndex = index; - if (unsigned(index) >= submesh->Surfaces.Size()) + if (unsigned(index) >= Surfaces.Size()) { fprintf(f, "o Surface[%d] (bad index)\n", index); fprintf(f, "usemtl error\n"); @@ -319,12 +908,12 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen } else { - const auto& surface = submesh->Surfaces[index]; + const auto& surface = Surfaces[index]; fprintf(f, "o Surface[%d] %s %d%s\n", index, name(surface.Type), surface.TypeIndex, surface.IsSky ? " sky" : ""); if (surface.LightmapTileIndex >= 0) { - auto& tile = submesh->LightmapTiles[surface.LightmapTileIndex]; + auto& tile = LightmapTiles[surface.LightmapTileIndex]; fprintf(f, "usemtl lightmap%d\n", tile.AtlasLocation.ArrayIndex); if (tile.AtlasLocation.ArrayIndex > highestUsedAtlasPage) @@ -337,9 +926,9 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen // fprintf(f, "f %d %d %d\n", MeshElements[i] + 1, MeshElements[i + 1] + 1, MeshElements[i + 2] + 1); fprintf(f, "f %d/%d %d/%d %d/%d\n", - submesh->Mesh.Indexes[i + 0] + 1, submesh->Mesh.Indexes[i + 0] + 1, - submesh->Mesh.Indexes[i + 1] + 1, submesh->Mesh.Indexes[i + 1] + 1, - submesh->Mesh.Indexes[i + 2] + 1, submesh->Mesh.Indexes[i + 2] + 1); + Mesh.Indexes[i + 0] + 1, Mesh.Indexes[i + 0] + 1, + Mesh.Indexes[i + 1] + 1, Mesh.Indexes[i + 1] + 1, + Mesh.Indexes[i + 2] + 1, Mesh.Indexes[i + 2] + 1); } diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 0aa48ac98..85fdad6f5 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -2,13 +2,40 @@ #pragma once #include "hw_levelmesh.h" -#include "doom_levelsubmesh.h" +#include "scene/hw_drawstructs.h" +#include "tarray.h" +#include "vectors.h" +#include "r_defs.h" +#include "bounds.h" +#include +#include + +struct FLevelLocals; +struct FPolyObj; +struct HWWallDispatcher; +class DoomLevelMesh; +class MeshBuilder; + +struct DoomLevelMeshSurface : public LevelMeshSurface +{ + DoomLevelMeshSurfaceType Type = ST_NONE; + int TypeIndex = 0; + + subsector_t* Subsector = nullptr; + side_t* Side = nullptr; + sector_t* ControlSector = nullptr; + + int PipelineID = 0; +}; class DoomLevelMesh : public LevelMesh { public: DoomLevelMesh(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(surface) - Surfaces.Data()); } + int GetSurfaceCount() override { return Surfaces.Size(); } int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) override; void BeginFrame(FLevelLocals& doomMap); @@ -17,11 +44,34 @@ public: void BuildSectorGroups(const FLevelLocals& doomMap); + TArray Surfaces; + TArray> PolyLMSurfaces; + TArray WallPortals; + TArray sectorGroup; // index is sector, value is sectorGroup TArray sectorPortals[2]; // index is sector+plane, value is index into the portal list TArray linePortals; // index is linedef, value is index into the portal list private: + void Reset(); + + void CreateSurfaces(FLevelLocals& doomMap); + + void SetSubsectorLightmap(DoomLevelMeshSurface* surface); + void SetSideLightmap(DoomLevelMeshSurface* surface); + + void SortIndexes(); + + void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky, bool translucent); + void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky = false); + + void LinkSurfaces(FLevelLocals& doomMap); + + BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const; + + int AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map& bindings); + int GetSampleDimension(const DoomLevelMeshSurface& surf); + void CreatePortals(FLevelLocals& doomMap); FLightNode* GetSurfaceLightNode(const DoomLevelMeshSurface* doomsurf); }; diff --git a/src/rendering/hwrenderer/doom_levelsubmesh.cpp b/src/rendering/hwrenderer/doom_levelsubmesh.cpp deleted file mode 100644 index 71554da39..000000000 --- a/src/rendering/hwrenderer/doom_levelsubmesh.cpp +++ /dev/null @@ -1,627 +0,0 @@ - -#include "templates.h" -#include "doom_levelsubmesh.h" -#include "g_levellocals.h" -#include "texturemanager.h" -#include "playsim/p_lnspec.h" -#include "c_dispatch.h" -#include "g_levellocals.h" -#include "a_dynlight.h" -#include "hw_renderstate.h" -#include "hw_vertexbuilder.h" -#include "hwrenderer/scene/hw_drawstructs.h" -#include "hwrenderer/scene/hw_drawinfo.h" -#include "hwrenderer/scene/hw_walldispatcher.h" -#include "hwrenderer/scene/hw_flatdispatcher.h" -#include "common/rendering/hwrenderer/data/hw_meshbuilder.h" -#include - -EXTERN_CVAR(Float, lm_scale); - -DoomLevelSubmesh::DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, bool staticMesh) : LevelMesh(mesh), StaticMesh(staticMesh) -{ - LightmapSampleDistance = doomMap.LightmapSampleDistance; - Reset(); - - if (StaticMesh) - { - CreateStaticSurfaces(doomMap); - LinkSurfaces(doomMap); - - SortIndexes(); - BuildTileSurfaceLists(); - UpdateCollision(); - } -} - -void DoomLevelSubmesh::Update(FLevelLocals& doomMap) -{ - if (!StaticMesh) - { - Reset(); - - CreateDynamicSurfaces(doomMap); - LinkSurfaces(doomMap); - - SortIndexes(); - BuildTileSurfaceLists(); - UpdateCollision(); - } -} - -void DoomLevelSubmesh::Reset() -{ - Surfaces.Clear(); - Portals.Clear(); - Mesh.Vertices.Clear(); - Mesh.Indexes.Clear(); - Mesh.SurfaceIndexes.Clear(); - Mesh.UniformIndexes.Clear(); - Mesh.Uniforms.Clear(); - Mesh.Materials.Clear(); -} - -void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap) -{ - // We can't use side->segs since it is null. - TArray> sideSegs(doomMap.sides.Size(), true); - for (unsigned int i = 0; i < doomMap.subsectors.Size(); i++) - { - subsector_t* sub = &doomMap.subsectors[i]; - sector_t* sector = sub->sector; - for (int i = 0, count = sub->numlines; i < count; i++) - { - seg_t* seg = sub->firstline + i; - if (seg->sidedef) - sideSegs[seg->sidedef->Index()] = { sub, seg }; - } - } - - MeshBuilder state; - std::map bindings; - - // Create surface objects for all sides - for (unsigned int i = 0; i < doomMap.sides.Size(); i++) - { - side_t* side = &doomMap.sides[i]; - bool isPolyLine = !!(side->Flags & WALLF_POLYOBJ); - if (isPolyLine) - continue; - - subsector_t* sub = sideSegs[i].first; - seg_t* seg = sideSegs[i].second; - if (!seg) - continue; - - sector_t* front = side->sector; - sector_t* back = (side->linedef->frontsector == front) ? side->linedef->backsector : side->linedef->frontsector; - - HWMeshHelper result; - HWWallDispatcher disp(&doomMap, &result, getRealLightmode(&doomMap, true)); - HWWall wall; - wall.sub = sub; - wall.Process(&disp, state, seg, front, back); - - // Part 1: solid geometry. This is set up so that there are no transparent parts - state.SetDepthFunc(DF_LEqual); - state.ClearDepthBias(); - state.EnableTexture(true); - state.EnableBrightmap(true); - state.AlphaFunc(Alpha_GEqual, 0.f); - CreateWallSurface(side, disp, state, bindings, result.list, false, true); - - for (HWWall& portal : result.portals) - { - Portals.Push(portal); - } - - CreateWallSurface(side, disp, state, bindings, result.portals, true, false); - - /* - // final pass: translucent stuff - state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); - state.SetRenderStyle(STYLE_Translucent); - CreateWallSurface(side, disp, state, bindings, result.translucent, false, true); - state.AlphaFunc(Alpha_GEqual, 0.f); - state.SetRenderStyle(STYLE_Normal); - */ - } - - // Create surfaces for all flats - for (unsigned int i = 0; i < doomMap.sectors.Size(); i++) - { - sector_t* sector = &doomMap.sectors[i]; - if (sector->subsectors[0]->flags & SSECF_POLYORG) - continue; - for (FSection& section : doomMap.sections.SectionsForSector(i)) - { - int sectionIndex = doomMap.sections.SectionIndex(§ion); - - HWFlatMeshHelper result; - HWFlatDispatcher disp(&doomMap, &result, getRealLightmode(&doomMap, true)); - - HWFlat flat; - flat.section = §ion; - flat.ProcessSector(&disp, state, sector); - - // Part 1: solid geometry. This is set up so that there are no transparent parts - state.SetDepthFunc(DF_LEqual); - state.ClearDepthBias(); - state.EnableTexture(true); - state.EnableBrightmap(true); - CreateFlatSurface(disp, state, bindings, result.list); - - CreateFlatSurface(disp, state, bindings, result.portals, true); - - // final pass: translucent stuff - state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); - state.SetRenderStyle(STYLE_Translucent); - CreateFlatSurface(disp, state, bindings, result.translucentborder); - state.SetDepthMask(false); - CreateFlatSurface(disp, state, bindings, result.translucent); - state.AlphaFunc(Alpha_GEqual, 0.f); - state.SetDepthMask(true); - state.SetRenderStyle(STYLE_Normal); - } - } -} - -void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky, bool translucent) -{ - for (HWWall& wallpart : list) - { - if (isSky) - { - state.SetEffect(EFF_PORTAL); - state.EnableTexture(false); - state.SetRenderStyle(STYLE_Normal); - - wallpart.MakeVertices(state, false); - wallpart.RenderWall(state, HWWall::RWF_BLANK); - wallpart.vertcount = 0; - - wallpart.LevelMeshInfo.Type = ST_NONE; - wallpart.LevelMeshInfo.ControlSector = nullptr; - - state.SetEffect(EFF_NONE); - state.EnableTexture(true); - } - else - { - if (wallpart.texture && wallpart.texture->isMasked()) - { - state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); - } - else - { - state.AlphaFunc(Alpha_GEqual, 0.f); - } - - wallpart.DrawWall(&disp, state, translucent); - } - - int pipelineID = 0; - int startVertIndex = Mesh.Vertices.Size(); - int startElementIndex = Mesh.Indexes.Size(); - for (auto& it : state.mSortedLists) - { - const MeshApplyState& applyState = it.first; - - pipelineID = screen->GetLevelMeshPipelineID(applyState.applyData, applyState.surfaceUniforms, applyState.material); - - int uniformsIndex = Mesh.Uniforms.Size(); - Mesh.Uniforms.Push(applyState.surfaceUniforms); - Mesh.Materials.Push(applyState.material); - - for (MeshDrawCommand& command : it.second.mDraws) - { - for (int i = command.Start, end = command.Start + command.Count; i < end; i++) - { - Mesh.Vertices.Push(state.mVertices[i]); - Mesh.UniformIndexes.Push(uniformsIndex); - } - - if (command.DrawType == DT_TriangleFan) - { - for (int i = 2, count = command.Count; i < count; i++) - { - Mesh.Indexes.Push(startVertIndex); - Mesh.Indexes.Push(startVertIndex + i - 1); - Mesh.Indexes.Push(startVertIndex + i); - } - } - } - } - state.mSortedLists.clear(); - state.mVertices.Clear(); - state.mIndexes.Clear(); - - FVector2 v1 = FVector2(side->V1()->fPos()); - FVector2 v2 = FVector2(side->V2()->fPos()); - FVector2 N = FVector2(v2.Y - v1.Y, v1.X - v2.X).Unit(); - - DoomLevelMeshSurface surf; - surf.Submesh = this; - surf.Type = wallpart.LevelMeshInfo.Type; - surf.ControlSector = wallpart.LevelMeshInfo.ControlSector; - surf.TypeIndex = side->Index(); - surf.Side = side; - surf.AlwaysUpdate = !!(side->sector->Flags & SECF_LM_DYNAMIC); - surf.SectorGroup = LevelMesh->sectorGroup[side->sector->Index()]; - surf.Alpha = float(side->linedef->alpha); - surf.MeshLocation.StartVertIndex = startVertIndex; - surf.MeshLocation.StartElementIndex = startElementIndex; - surf.MeshLocation.NumVerts = Mesh.Vertices.Size() - startVertIndex; - surf.MeshLocation.NumElements = Mesh.Indexes.Size() - startElementIndex; - surf.Plane = FVector4(N.X, N.Y, 0.0f, v1 | N); - surf.Texture = wallpart.texture; - surf.PipelineID = pipelineID; - surf.PortalIndex = isSky ? LevelMesh->linePortals[side->linedef->Index()] : 0; - surf.IsSky = isSky; - surf.Bounds = GetBoundsFromSurface(surf); - surf.LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(surf, bindings) : -1; - Surfaces.Push(surf); - } -} - -int DoomLevelSubmesh::AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map& bindings) -{ - if (surf.IsSky) - return -1; - - LightmapTileBinding binding; - binding.Type = surf.Type; - binding.TypeIndex = surf.TypeIndex; - binding.ControlSector = surf.ControlSector ? surf.ControlSector->Index() : (int)0xffffffffUL; - - auto it = bindings.find(binding); - if (it != bindings.end()) - { - int index = it->second; - - LightmapTile& tile = LightmapTiles[index]; - tile.Bounds.min.X = std::min(tile.Bounds.min.X, surf.Bounds.min.X); - tile.Bounds.min.Y = std::min(tile.Bounds.min.Y, surf.Bounds.min.Y); - tile.Bounds.min.Z = std::min(tile.Bounds.min.Z, surf.Bounds.min.Z); - tile.Bounds.max.X = std::max(tile.Bounds.max.X, surf.Bounds.max.X); - tile.Bounds.max.Y = std::max(tile.Bounds.max.Y, surf.Bounds.max.Y); - tile.Bounds.max.Z = std::max(tile.Bounds.max.Z, surf.Bounds.max.Z); - - return index; - } - else - { - int index = LightmapTiles.Size(); - - LightmapTile tile; - tile.Binding = binding; - tile.Bounds = surf.Bounds; - tile.Plane = surf.Plane; - tile.SampleDimension = GetSampleDimension(surf); - - LightmapTiles.Push(tile); - bindings[binding] = index; - return index; - } -} - -int DoomLevelSubmesh::GetSampleDimension(const DoomLevelMeshSurface& surf) -{ - uint16_t sampleDimension = 0; // To do: something seems to have gone missing with the sample dimension! - - if (sampleDimension <= 0) - { - sampleDimension = LightmapSampleDistance; - } - - sampleDimension = uint16_t(max(int(roundf(float(sampleDimension) / max(1.0f / 4, float(lm_scale)))), 1)); - - // Round to nearest power of two - uint32_t n = uint16_t(sampleDimension); - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - n = (n + 1) >> 1; - sampleDimension = uint16_t(n) ? uint16_t(n) : uint16_t(0xFFFF); - - return sampleDimension; -} - -void DoomLevelSubmesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky) -{ - for (HWFlat& flatpart : list) - { - if (isSky) - { - state.SetEffect(EFF_PORTAL); - state.EnableTexture(false); - state.SetRenderStyle(STYLE_Normal); - - flatpart.DrawSubsectors(&disp, state); - - state.SetEffect(EFF_NONE); - state.EnableTexture(true); - } - else - { - if (flatpart.texture && flatpart.texture->isMasked()) - { - state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); - } - else - { - state.AlphaFunc(Alpha_GEqual, 0.f); - } - - flatpart.DrawFlat(&disp, state, false); - } - - VSMatrix textureMatrix; - textureMatrix.loadIdentity(); - - int pipelineID = 0; - int uniformsIndex = 0; - bool foundDraw = false; - for (auto& it : state.mSortedLists) - { - const MeshApplyState& applyState = it.first; - - pipelineID = screen->GetLevelMeshPipelineID(applyState.applyData, applyState.surfaceUniforms, applyState.material); - uniformsIndex = Mesh.Uniforms.Size(); - textureMatrix = applyState.textureMatrix; - Mesh.Uniforms.Push(applyState.surfaceUniforms); - Mesh.Materials.Push(applyState.material); - - foundDraw = true; - break; - } - state.mSortedLists.clear(); - state.mVertices.Clear(); - state.mIndexes.Clear(); - - if (!foundDraw) - continue; - - DoomLevelMeshSurface surf; - surf.Submesh = this; - surf.Type = flatpart.ceiling ? ST_CEILING : ST_FLOOR; - surf.ControlSector = flatpart.controlsector ? flatpart.controlsector->model : nullptr; - surf.AlwaysUpdate = !!(flatpart.sector->Flags & SECF_LM_DYNAMIC); - surf.SectorGroup = LevelMesh->sectorGroup[flatpart.sector->Index()]; - surf.Alpha = flatpart.alpha; - surf.Texture = flatpart.texture; - surf.PipelineID = pipelineID; - surf.PortalIndex = LevelMesh->sectorPortals[flatpart.ceiling][flatpart.sector->Index()]; - surf.IsSky = isSky; - - auto plane = surf.ControlSector ? surf.ControlSector->GetSecPlane(!flatpart.ceiling) : flatpart.sector->GetSecPlane(flatpart.ceiling); - surf.Plane = FVector4((float)plane.Normal().X, (float)plane.Normal().Y, (float)plane.Normal().Z, -(float)plane.D); - - if (surf.ControlSector) - surf.Plane = -surf.Plane; - - float skyZ = flatpart.ceiling ? 32768.0f : -32768.0f; - - for (subsector_t* sub : flatpart.section->subsectors) - { - if (sub->numlines < 3) - continue; - - int startVertIndex = Mesh.Vertices.Size(); - int startElementIndex = Mesh.Indexes.Size(); - - for (int i = 0, end = sub->numlines; i < end; i++) - { - auto& vt = sub->firstline[end - 1 - i].v1; - - FVector3 pt((float)vt->fX(), (float)vt->fY(), isSky ? skyZ : (float)plane.ZatPoint(vt)); - FVector4 uv = textureMatrix * FVector4(pt.X * (1.0f / 64.0f), pt.Y * (-1.0f / 64.0f), 0.0f, 1.0f); - - FFlatVertex ffv; - ffv.x = pt.X; - ffv.y = pt.Y; - ffv.z = pt.Z; - ffv.u = uv.X; - ffv.v = uv.Y; - ffv.lu = 0.0f; - ffv.lv = 0.0f; - ffv.lindex = -1.0f; - - Mesh.Vertices.Push(ffv); - Mesh.UniformIndexes.Push(uniformsIndex); - } - - if (flatpart.ceiling) - { - for (int i = 2, count = sub->numlines; i < count; i++) - { - Mesh.Indexes.Push(startVertIndex); - Mesh.Indexes.Push(startVertIndex + i - 1); - Mesh.Indexes.Push(startVertIndex + i); - } - } - else - { - for (int i = 2, count = sub->numlines; i < count; i++) - { - Mesh.Indexes.Push(startVertIndex + i); - Mesh.Indexes.Push(startVertIndex + i - 1); - Mesh.Indexes.Push(startVertIndex); - } - } - - surf.TypeIndex = sub->Index(); - surf.Subsector = sub; - surf.MeshLocation.StartVertIndex = startVertIndex; - surf.MeshLocation.StartElementIndex = startElementIndex; - surf.MeshLocation.NumVerts = sub->numlines; - surf.MeshLocation.NumElements = (sub->numlines - 2) * 3; - surf.Bounds = GetBoundsFromSurface(surf); - surf.LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(surf, bindings) : -1; - Surfaces.Push(surf); - } - } -} - -void DoomLevelSubmesh::CreateDynamicSurfaces(FLevelLocals& doomMap) -{ -#if 0 - // Look for polyobjects - for (unsigned int i = 0; i < doomMap.lines.Size(); i++) - { - side_t* side = doomMap.lines[i].sidedef[0]; - bool isPolyLine = !!(side->Flags & WALLF_POLYOBJ); - if (!isPolyLine) - continue; - - // Make sure we have a surface array on the polyobj sidedef - if (!side->surface) - { - auto array = std::make_unique(4); - memset(array.get(), 0, sizeof(DoomLevelMeshSurface*)); - side->surface = array.get(); - PolyLMSurfaces.Push(std::move(array)); - } - - CreateSideSurfaces(doomMap, side); - } -#endif -} - -void DoomLevelSubmesh::SortIndexes() -{ - // Order surfaces by pipeline - std::unordered_map> pipelineSurfaces; - for (size_t i = 0; i < Surfaces.Size(); i++) - { - DoomLevelMeshSurface* s = &Surfaces[i]; - pipelineSurfaces[(int64_t(s->PipelineID) << 32) | int64_t(s->IsSky)].Push(i); - } - - // Create reorder surface indexes by pipeline and create a draw range for each - TArray sortedIndexes; - for (const auto& it : pipelineSurfaces) - { - LevelSubmeshDrawRange range; - range.PipelineID = it.first >> 32; - range.Start = sortedIndexes.Size(); - - // Move indexes to new array - for (unsigned int i : it.second) - { - DoomLevelMeshSurface& s = Surfaces[i]; - - unsigned int start = s.MeshLocation.StartElementIndex; - unsigned int count = s.MeshLocation.NumElements; - - s.MeshLocation.StartElementIndex = sortedIndexes.Size(); - - for (unsigned int j = 0; j < count; j++) - { - sortedIndexes.Push(Mesh.Indexes[start + j]); - } - - for (unsigned int j = 0; j < count; j += 3) - { - Mesh.SurfaceIndexes.Push((int)i); - } - } - - range.Count = sortedIndexes.Size() - range.Start; - - if ((it.first & 1) == 0) - DrawList.Push(range); - else - PortalList.Push(range); - } - - Mesh.Indexes.Swap(sortedIndexes); -} - -void DoomLevelSubmesh::LinkSurfaces(FLevelLocals& doomMap) -{ - for (auto& surface : Surfaces) - { - if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING) - { - SetSubsectorLightmap(&surface); - } - else - { - SetSideLightmap(&surface); - } - } -} - -void DoomLevelSubmesh::SetSubsectorLightmap(DoomLevelMeshSurface* surface) -{ - if (surface->Subsector->firstline && surface->Subsector->firstline->sidedef) - surface->Subsector->firstline->sidedef->sector->HasLightmaps = true; - - if (!surface->ControlSector) - { - int index = surface->Type == ST_CEILING ? 1 : 0; - surface->Subsector->surface[index][0] = surface; - } - else - { - int index = surface->Type == ST_CEILING ? 0 : 1; - const auto& ffloors = surface->Subsector->sector->e->XFloor.ffloors; - for (unsigned int i = 0; i < ffloors.Size(); i++) - { - if (ffloors[i]->model == surface->ControlSector) - { - surface->Subsector->surface[index][i + 1] = surface; - } - } - } -} - -void DoomLevelSubmesh::SetSideLightmap(DoomLevelMeshSurface* surface) -{ - if (!surface->ControlSector) - { - if (surface->Type == ST_UPPERSIDE) - { - surface->Side->surface[0] = surface; - } - else if (surface->Type == ST_MIDDLESIDE) - { - surface->Side->surface[1] = surface; - surface->Side->surface[2] = surface; - } - else if (surface->Type == ST_LOWERSIDE) - { - surface->Side->surface[3] = surface; - } - } - else - { - const auto& ffloors = surface->Side->sector->e->XFloor.ffloors; - for (unsigned int i = 0; i < ffloors.Size(); i++) - { - if (ffloors[i]->model == surface->ControlSector) - { - surface->Side->surface[4 + i] = surface; - } - } - } -} - -BBox DoomLevelSubmesh::GetBoundsFromSurface(const LevelMeshSurface& surface) const -{ - BBox bounds; - bounds.Clear(); - for (int i = int(surface.MeshLocation.StartVertIndex); i < int(surface.MeshLocation.StartVertIndex) + surface.MeshLocation.NumVerts; i++) - { - FVector3 v = Mesh.Vertices[(int)i].fPos(); - bounds.min.X = std::min(bounds.min.X, v.X); - bounds.min.Y = std::min(bounds.min.Y, v.Y); - bounds.min.Z = std::min(bounds.min.Z, v.Z); - bounds.max.X = std::max(bounds.max.X, v.X); - bounds.max.Y = std::max(bounds.max.Y, v.Y); - bounds.max.Z = std::max(bounds.max.Z, v.Z); - } - return bounds; -} diff --git a/src/rendering/hwrenderer/doom_levelsubmesh.h b/src/rendering/hwrenderer/doom_levelsubmesh.h deleted file mode 100644 index 3bb3d8717..000000000 --- a/src/rendering/hwrenderer/doom_levelsubmesh.h +++ /dev/null @@ -1,71 +0,0 @@ - -#pragma once - -#include "hw_levelmesh.h" -#include "scene/hw_drawstructs.h" -#include "tarray.h" -#include "vectors.h" -#include "r_defs.h" -#include "bounds.h" -#include -#include - -struct FLevelLocals; -struct FPolyObj; -struct HWWallDispatcher; -class DoomLevelMesh; -class MeshBuilder; - -struct DoomLevelMeshSurface : public LevelMeshSurface -{ - DoomLevelMeshSurfaceType Type = ST_NONE; - int TypeIndex = 0; - - subsector_t* Subsector = nullptr; - side_t* Side = nullptr; - sector_t* ControlSector = nullptr; - - int PipelineID = 0; -}; - -class DoomLevelSubmesh : public LevelSubmesh -{ -public: - DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, bool staticMesh); - - 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(surface) - Surfaces.Data()); } - int GetSurfaceCount() override { return Surfaces.Size(); } - - TArray Surfaces; - TArray> PolyLMSurfaces; - TArray Portals; - -private: - void Reset(); - - void CreateStaticSurfaces(FLevelLocals& doomMap); - void CreateDynamicSurfaces(FLevelLocals& doomMap); - - void SetSubsectorLightmap(DoomLevelMeshSurface* surface); - void SetSideLightmap(DoomLevelMeshSurface* surface); - - void SortIndexes(); - - void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky, bool translucent); - void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map& bindings, TArray& list, bool isSky = false); - - void LinkSurfaces(FLevelLocals& doomMap); - - BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const; - - int AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map& bindings); - int GetSampleDimension(const DoomLevelMeshSurface& surf); - - DoomLevelMesh* LevelMesh = nullptr; - bool StaticMesh = true; -}; - -static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2); diff --git a/src/rendering/hwrenderer/hw_vertexbuilder.cpp b/src/rendering/hwrenderer/hw_vertexbuilder.cpp index 1dff841c2..2e64a07ed 100644 --- a/src/rendering/hwrenderer/hw_vertexbuilder.cpp +++ b/src/rendering/hwrenderer/hw_vertexbuilder.cpp @@ -246,7 +246,7 @@ static int CreateIndexedSectorVerticesLM(sector_t* sec, const secplane_t& plane, DoomLevelMeshSurface* lightmap = sub->surface[h].Size() > lightmapIndex ? sub->surface[h][lightmapIndex] : nullptr; if (lightmap && lightmap->Type != ST_NONE) // surface may be missing if the subsector is degenerate triangle { - FFlatVertex* luvs = &lightmap->Submesh->Mesh.Vertices[lightmap->MeshLocation.StartVertIndex]; + FFlatVertex* luvs = &level.levelMesh->Mesh.Vertices[lightmap->MeshLocation.StartVertIndex]; for (unsigned int j = 0, end = sub->numlines; j < end; j++) { SetFlatVertex(vbo_shadowdata[vi + pos], sub->firstline[j].v1, plane, luvs[end - 1 - j].lu, luvs[end - 1 - j].lv, luvs[end - 1 - j].lindex); diff --git a/src/rendering/hwrenderer/scene/hw_decal.cpp b/src/rendering/hwrenderer/scene/hw_decal.cpp index baa94985a..cc0dd456c 100644 --- a/src/rendering/hwrenderer/scene/hw_decal.cpp +++ b/src/rendering/hwrenderer/scene/hw_decal.cpp @@ -424,12 +424,12 @@ void HWWall::ProcessDecal(HWDrawInfo *di, FRenderState& state, DBaseDecal *decal if (surface && surface->LightmapTileIndex >= 0) { - LightmapTile* tile = &surface->Submesh->LightmapTiles[surface->LightmapTileIndex]; + LightmapTile* tile = &di->Level->levelMesh->LightmapTiles[surface->LightmapTileIndex]; float lightmapindex = (float)tile->AtlasLocation.ArrayIndex; for (i = 0; i < 4; i++) { - FVector2 lightmapuv = tile->ToUV(FVector3(dv[i].x, dv[i].y, dv[i].z), surface->Submesh->LMTextureSize); + FVector2 lightmapuv = tile->ToUV(FVector3(dv[i].x, dv[i].y, dv[i].z), di->Level->levelMesh->LMTextureSize); verts.first[i].Set(dv[i].x, dv[i].z, dv[i].y, dv[i].u, dv[i].v, lightmapuv.X, lightmapuv.Y, lightmapindex); } } diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index b1cec2e67..2384d0c46 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -411,7 +411,7 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state) validcount++; // used for processing sidedefs only once by the renderer. - auto& portals = static_cast(level.levelMesh->StaticMesh.get())->Portals; + auto& portals = level.levelMesh->WallPortals; // draw level into depth buffer state.SetColorMask(false); @@ -622,7 +622,7 @@ void HWDrawInfo::UpdateLightmaps() { if (!outer && VisibleTiles.Size() < unsigned(lm_background_updates)) { - for (auto& e : level.levelMesh->StaticMesh->LightmapTiles) + for (auto& e : level.levelMesh->LightmapTiles) { if (e.NeedsUpdate) { diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index b455d847c..e67bb77a6 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -10,6 +10,7 @@ #include "hw_weapon.h" #include "hw_drawlist.h" #include "hw_renderstate.h" +#include "g_levellocals.h" EXTERN_CVAR(Bool, lm_always_update); EXTERN_CVAR(Int, lm_max_updates); @@ -235,7 +236,7 @@ public: if (surface->LightmapTileIndex < 0) return; - LightmapTile* tile = &surface->Submesh->LightmapTiles[surface->LightmapTileIndex]; + LightmapTile* tile = &Level->levelMesh->LightmapTiles[surface->LightmapTileIndex]; if (lm_always_update || surface->AlwaysUpdate) { tile->NeedsUpdate = true; diff --git a/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp b/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp index adb4d52f7..52b13763c 100644 --- a/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls_vertex.cpp @@ -26,7 +26,8 @@ #include "hw_renderstate.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_drawstructs.h" -#include "doom_levelsubmesh.h" +#include "doom_levelmesh.h" +#include "g_levellocals.h" EXTERN_CVAR(Bool, gl_seamless) @@ -196,11 +197,11 @@ int HWWall::CreateVertices(FFlatVertex *&ptr, bool split) { if (surface && surface->LightmapTileIndex >= 0) { - LightmapTile* tile = &surface->Submesh->LightmapTiles[surface->LightmapTileIndex]; - FVector2 lolft = tile->ToUV(FVector3(glseg.x1, glseg.y1, zbottom[0]), surface->Submesh->LMTextureSize); - FVector2 uplft = tile->ToUV(FVector3(glseg.x1, glseg.y1, ztop[0]), surface->Submesh->LMTextureSize); - FVector2 uprgt = tile->ToUV(FVector3(glseg.x2, glseg.y2, ztop[1]), surface->Submesh->LMTextureSize); - FVector2 lorgt = tile->ToUV(FVector3(glseg.x2, glseg.y2, zbottom[1]), surface->Submesh->LMTextureSize); + LightmapTile* tile = &level.levelMesh->LightmapTiles[surface->LightmapTileIndex]; + FVector2 lolft = tile->ToUV(FVector3(glseg.x1, glseg.y1, zbottom[0]), level.levelMesh->LMTextureSize); + FVector2 uplft = tile->ToUV(FVector3(glseg.x1, glseg.y1, ztop[0]), level.levelMesh->LMTextureSize); + FVector2 uprgt = tile->ToUV(FVector3(glseg.x2, glseg.y2, ztop[1]), level.levelMesh->LMTextureSize); + FVector2 lorgt = tile->ToUV(FVector3(glseg.x2, glseg.y2, zbottom[1]), level.levelMesh->LMTextureSize); lightuv[LOLFT] = { lolft.X, lolft.Y }; lightuv[UPLFT] = { uplft.X, uplft.Y }; lightuv[UPRGT] = { uprgt.X, uprgt.Y };