Remove the submesh class as that caused more problems than it solved
This commit is contained in:
parent
d9c896a903
commit
7bc2ed5436
20 changed files with 836 additions and 994 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<TriangleMeshShape>(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<TriangleMeshShape>(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size());
|
||||
}
|
||||
|
||||
struct LevelMeshPlaneGroup
|
||||
|
|
@ -120,7 +109,7 @@ struct LevelMeshPlaneGroup
|
|||
std::vector<LevelMeshSurface*> surfaces;
|
||||
};
|
||||
|
||||
void LevelSubmesh::BuildTileSurfaceLists()
|
||||
void LevelMesh::BuildTileSurfaceLists()
|
||||
{
|
||||
// Plane group surface is to be rendered with
|
||||
TArray<LevelMeshPlaneGroup> 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<LightmapTile*> sortedTiles;
|
||||
sortedTiles.reserve(LightmapTiles.Size());
|
||||
|
|
|
|||
|
|
@ -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<LevelMeshPortal> Portals;
|
||||
|
||||
struct
|
||||
{
|
||||
// Vertex data
|
||||
TArray<FFlatVertex> Vertices;
|
||||
TArray<uint32_t> Indexes;
|
||||
TArray<int> SurfaceIndexes;
|
||||
TArray<int> UniformIndexes;
|
||||
|
||||
// Surface info
|
||||
TArray<SurfaceUniforms> Uniforms;
|
||||
TArray<FMaterialState> Materials;
|
||||
|
||||
// Index data
|
||||
TArray<uint32_t> Indexes;
|
||||
TArray<int> 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<TriangleMeshShape> 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<LevelSubmesh> StaticMesh = std::make_unique<LevelSubmesh>();
|
||||
std::unique_ptr<LevelSubmesh> DynamicMesh = std::make_unique<LevelSubmesh>();
|
||||
|
||||
virtual int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { return 0; }
|
||||
|
||||
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<LevelMeshPortal> Portals;
|
||||
void AddEmptyMesh();
|
||||
};
|
||||
|
||||
struct LevelMeshTileStats
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ struct LightmapTile
|
|||
LightmapTileBinding Binding;
|
||||
|
||||
// Surfaces that are visible within the lightmap tile
|
||||
TArray<LevelMeshSurface*> Surfaces;
|
||||
TArray<int> Surfaces;
|
||||
|
||||
BBox Bounds;
|
||||
uint16_t SampleDimension = 0;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<LightmapTileBinding, LightmapTile*> 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;
|
||||
|
|
|
|||
|
|
@ -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 <unordered_map>
|
||||
|
||||
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<DoomLevelSubmesh>(this, doomMap, true);
|
||||
DynamicMesh = std::make_unique<DoomLevelSubmesh>(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<DoomLevelSubmesh*>(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<std::pair<subsector_t*, seg_t*>> 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<LightmapTileBinding, int> 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<LightmapTileBinding, int>& bindings, TArray<HWWall>& 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<LightmapTileBinding, int>& 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<LightmapTileBinding, int>& bindings, TArray<HWFlat>& 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<DoomLevelMeshSurface * []>(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<int64_t, TArray<int>> 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<uint32_t> 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<DoomLevelSubmesh*>(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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <set>
|
||||
#include <map>
|
||||
|
||||
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<const DoomLevelMeshSurface*>(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<DoomLevelMeshSurface> Surfaces;
|
||||
TArray<std::unique_ptr<DoomLevelMeshSurface* []>> PolyLMSurfaces;
|
||||
TArray<HWWall> WallPortals;
|
||||
|
||||
TArray<int> sectorGroup; // index is sector, value is sectorGroup
|
||||
TArray<int> sectorPortals[2]; // index is sector+plane, value is index into the portal list
|
||||
TArray<int> 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<LightmapTileBinding, int>& bindings, TArray<HWWall>& list, bool isSky, bool translucent);
|
||||
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWFlat>& list, bool isSky = false);
|
||||
|
||||
void LinkSurfaces(FLevelLocals& doomMap);
|
||||
|
||||
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
|
||||
|
||||
int AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map<LightmapTileBinding, int>& bindings);
|
||||
int GetSampleDimension(const DoomLevelMeshSurface& surf);
|
||||
|
||||
void CreatePortals(FLevelLocals& doomMap);
|
||||
FLightNode* GetSurfaceLightNode(const DoomLevelMeshSurface* doomsurf);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 <unordered_map>
|
||||
|
||||
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<std::pair<subsector_t*, seg_t*>> 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<LightmapTileBinding, int> 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<LightmapTileBinding, int>& bindings, TArray<HWWall>& 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<LightmapTileBinding, int>& 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<LightmapTileBinding, int>& bindings, TArray<HWFlat>& 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<DoomLevelMeshSurface * []>(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<int64_t, TArray<int>> 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<uint32_t> 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;
|
||||
}
|
||||
|
|
@ -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 <set>
|
||||
#include <map>
|
||||
|
||||
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<const DoomLevelMeshSurface*>(surface) - Surfaces.Data()); }
|
||||
int GetSurfaceCount() override { return Surfaces.Size(); }
|
||||
|
||||
TArray<DoomLevelMeshSurface> Surfaces;
|
||||
TArray<std::unique_ptr<DoomLevelMeshSurface*[]>> PolyLMSurfaces;
|
||||
TArray<HWWall> 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<LightmapTileBinding, int>& bindings, TArray<HWWall>& list, bool isSky, bool translucent);
|
||||
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, std::map<LightmapTileBinding, int>& bindings, TArray<HWFlat>& list, bool isSky = false);
|
||||
|
||||
void LinkSurfaces(FLevelLocals& doomMap);
|
||||
|
||||
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
|
||||
|
||||
int AddSurfaceToTile(const DoomLevelMeshSurface& surf, std::map<LightmapTileBinding, int>& bindings);
|
||||
int GetSampleDimension(const DoomLevelMeshSurface& surf);
|
||||
|
||||
DoomLevelMesh* LevelMesh = nullptr;
|
||||
bool StaticMesh = true;
|
||||
};
|
||||
|
||||
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DoomLevelSubmesh*>(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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue