diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index 1fce1faed..4549976cb 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -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 MeshVertices; TArray MeshVertexUVs; @@ -201,26 +228,26 @@ public: TArray MeshElements; TArray MeshSurfaceIndexes; - std::unique_ptr 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 Portals; + std::unique_ptr Collision; + // Lightmap atlas int LMTextureCount = 0; int LMTextureSize = 0; - TArray LMTextureData; // TODO better place for this? + TArray 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(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 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 StaticMesh = std::make_unique(); + std::unique_ptr DynamicMesh = std::make_unique(); + + 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 + } +}; diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index fa2b04aaf..efe72981f 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -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; diff --git a/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp b/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp index 236a1c943..b31a77b9a 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp @@ -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(NullMesh.MeshVertices.Data(), NullMesh.MeshVertices.Size(), NullMesh.MeshElements.Data(), NullMesh.MeshElements.Size()); - SetLevelMesh(nullptr); } @@ -99,17 +79,19 @@ void VkRaytrace::CreateBuffers() { std::vector nodes = CreateCollisionNodes(); + auto submesh = Mesh->StaticMesh.get(); + // std430 alignment rules forces us to convert the vec3 to a vec4 std::vector 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; - 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; - 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 VkRaytrace::CreateCollisionNodes() { + auto submesh = Mesh->StaticMesh.get(); + std::vector 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; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index 394288bcb..1cef1ded2 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -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); } } diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index 4e693974e..a7a232eab 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -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 zdraySurfaces; zdraySurfaces.Reserve(numSurfaces); - for (auto& surface : Level->levelMesh->Surfaces) + auto submesh = static_cast(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(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); } diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 8b040ff6c..22a8ca907 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -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(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(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(); + DynamicMesh = std::make_unique(); + + static_cast(StaticMesh.get())->CreateStatic(doomMap); + static_cast(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 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(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& 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 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(*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 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(meshlight)); - } - } - - node = node->nextLight; - } - } - } - - std::set 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 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; diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 226985043..fac36043c 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -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(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 Surfaces; - std::vector> Lights; TArray LightmapUvs; - static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2); - - // utility TArray sectorGroup; // index is sector, value is sectorGroup - // runtime utility variables - TMap> XFloorToSurface; - TMap> 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(StaticMesh.get())->PackLightmapAtlas(); + } + + void BindLightmapSurfacesToGeometry(FLevelLocals& doomMap) + { + static_cast(StaticMesh.get())->BindLightmapSurfacesToGeometry(doomMap); + + // Runtime helper + for (auto& surface : static_cast(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(StaticMesh.get())->DisableLightmaps(); + } + + void DumpMesh(const FString& objFilename, const FString& mtlFilename) const + { + static_cast(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> XFloorToSurface; + TMap> XFloorToSurfaceSides; }; diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 4e5b6f81e..c0dbe6709 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -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(level.levelMesh->StaticMesh.get())->Surfaces) { if (e.needsUpdate && !e.bSky && !e.portalIndex) {