From 43cef43e9b6a926a81bb5af81f97c594088cb0f0 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 28 Dec 2022 22:25:54 +0100 Subject: [PATCH] Add support for drawing flats into the mesh cache --- .../rendering/hwrenderer/data/hw_mesh.cpp | 18 +++++ .../rendering/hwrenderer/data/hw_mesh.h | 1 + .../hwrenderer/data/hw_meshbuilder.cpp | 17 ++++- .../hwrenderer/data/hw_meshbuilder.h | 3 +- src/maploader/maploader.cpp | 2 + src/rendering/hwrenderer/scene/hw_flats.cpp | 12 +-- .../hwrenderer/scene/hw_meshcache.cpp | 73 ++++++++++++++++++- src/rendering/hwrenderer/scene/hw_meshcache.h | 6 ++ 8 files changed, 120 insertions(+), 12 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_mesh.cpp b/src/common/rendering/hwrenderer/data/hw_mesh.cpp index 22f0998689..18e91b6457 100644 --- a/src/common/rendering/hwrenderer/data/hw_mesh.cpp +++ b/src/common/rendering/hwrenderer/data/hw_mesh.cpp @@ -45,6 +45,24 @@ void Mesh::Draw(FRenderState& renderstate) renderstate.Draw(cmd.DrawType, pair.second + cmd.Start, cmd.Count, apply); } + for (const MeshDrawCommand& cmd : mIndexedDraws) + { + bool apply = applyIndex != cmd.ApplyIndex; + if (apply) + { + int newDepthFunc = mApplys[cmd.ApplyIndex].DepthFunc; + if (depthFunc != newDepthFunc) + { + depthFunc = newDepthFunc; + renderstate.SetDepthFunc(depthFunc); + } + + applyIndex = cmd.ApplyIndex; + Apply(renderstate, mApplys[cmd.ApplyIndex]); + } + renderstate.DrawIndexed(cmd.DrawType, cmd.Start, cmd.Count, apply); + } + Apply(renderstate, origState); } diff --git a/src/common/rendering/hwrenderer/data/hw_mesh.h b/src/common/rendering/hwrenderer/data/hw_mesh.h index 0e3ddc7650..913ccde2ce 100644 --- a/src/common/rendering/hwrenderer/data/hw_mesh.h +++ b/src/common/rendering/hwrenderer/data/hw_mesh.h @@ -12,6 +12,7 @@ private: TArray mApplys; TArray mDraws; + TArray mIndexedDraws; TArray mVertices; friend class MeshBuilder; diff --git a/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp b/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp index 162493c94f..f9cdd2ddc0 100644 --- a/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp +++ b/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp @@ -31,6 +31,19 @@ void MeshBuilder::Draw(int dt, int index, int count, bool apply) mDraws.Push(command); } +void MeshBuilder::DrawIndexed(int dt, int index, int count, bool apply) +{ + if (apply) + Apply(); + + MeshDrawCommand command; + command.DrawType = dt; + command.Start = index; + command.Count = count; + command.ApplyIndex = mApplys.Size() - 1; + mIndexedDraws.Push(command); +} + void MeshBuilder::SetDepthFunc(int func) { mDepthFunc = func; @@ -67,16 +80,18 @@ void MeshBuilder::Apply() std::unique_ptr MeshBuilder::Create() { - if (mDraws.Size() == 0) + if (mDraws.Size() == 0 && mIndexedDraws.Size() == 0) return {}; auto mesh = std::make_unique(); mesh->mApplys = std::move(mApplys); mesh->mDraws = std::move(mDraws); + mesh->mIndexedDraws = std::move(mIndexedDraws); mesh->mVertices = std::move(mVertices); mApplys.Clear(); mDraws.Clear(); + mIndexedDraws.Clear(); mVertices.Clear(); return mesh; diff --git a/src/common/rendering/hwrenderer/data/hw_meshbuilder.h b/src/common/rendering/hwrenderer/data/hw_meshbuilder.h index 9f8adb5150..fc58255434 100644 --- a/src/common/rendering/hwrenderer/data/hw_meshbuilder.h +++ b/src/common/rendering/hwrenderer/data/hw_meshbuilder.h @@ -51,7 +51,7 @@ public: // Draw commands void Draw(int dt, int index, int count, bool apply = true) override; - void DrawIndexed(int dt, int index, int count, bool apply = true) override { } // TBD: this is only used for the sector flat rendering. + void DrawIndexed(int dt, int index, int count, bool apply = true) override; // Immediate render state change commands. These only change infrequently and should not clutter the render state. void SetDepthFunc(int func) override; @@ -81,6 +81,7 @@ private: TArray mApplys; TArray mDraws; + TArray mIndexedDraws; TArray mVertices; int mDepthFunc = 0; }; diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index 567eb1fe07..4a93078fdc 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -83,6 +83,7 @@ #include "vm.h" #include "texturemanager.h" #include "hw_vertexbuilder.h" +#include "scene/hw_meshcache.h" #include "version.h" enum @@ -3243,6 +3244,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) InitRenderInfo(); // create hardware independent renderer resources for the level. This must be done BEFORE the PolyObj Spawn!!! Level->ClearDynamic3DFloorData(); // CreateVBO must be run on the plain 3D floor data. CreateVBO(screen->mVertexData, Level->sectors); + meshcache.Clear(); screen->InitLightmap(Level->LMTextureSize, Level->LMTextureCount, Level->LMTextureData); diff --git a/src/rendering/hwrenderer/scene/hw_flats.cpp b/src/rendering/hwrenderer/scene/hw_flats.cpp index 5b57c9f942..518f6b18c0 100644 --- a/src/rendering/hwrenderer/scene/hw_flats.cpp +++ b/src/rendering/hwrenderer/scene/hw_flats.cpp @@ -515,7 +515,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) // // // - if ((which & SSRF_RENDERFLOOR) && frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERFLOOR))) + if ((which & SSRF_RENDERFLOOR) && (di->MeshBuilding || frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z) && (!section || !(section->flags & FSection::DONTRENDERFLOOR))) { // process the original floor first. @@ -573,7 +573,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) // // // - if ((which & SSRF_RENDERCEILING) && frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERCEILING))) + if ((which & SSRF_RENDERCEILING) && (di->MeshBuilding || frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z) && (!section || !(section->flags & FSection::DONTRENDERCEILING))) { // process the original ceiling first. @@ -658,7 +658,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_top = rover->top.plane->ZatPoint(sector->centerspot); if (ff_top < lastceilingheight) { - if (vp.Pos.Z <= rover->top.plane->ZatPoint(vp.Pos)) + if (di->MeshBuilding || vp.Pos.Z <= rover->top.plane->ZatPoint(vp.Pos)) { SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG)); Colormap.FadeColor = frontsector->Colormap.FadeColor; @@ -672,7 +672,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot); if (ff_bottom < lastceilingheight) { - if (vp.Pos.Z <= rover->bottom.plane->ZatPoint(vp.Pos)) + if (di->MeshBuilding || vp.Pos.Z <= rover->bottom.plane->ZatPoint(vp.Pos)) { SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG)); Colormap.FadeColor = frontsector->Colormap.FadeColor; @@ -698,7 +698,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot); if (ff_bottom > lastfloorheight || (rover->flags&FF_FIX)) { - if (vp.Pos.Z >= rover->bottom.plane->ZatPoint(vp.Pos)) + if (di->MeshBuilding || vp.Pos.Z >= rover->bottom.plane->ZatPoint(vp.Pos)) { SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG)); Colormap.FadeColor = frontsector->Colormap.FadeColor; @@ -719,7 +719,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_top = rover->top.plane->ZatPoint(sector->centerspot); if (ff_top > lastfloorheight) { - if (vp.Pos.Z >= rover->top.plane->ZatPoint(vp.Pos)) + if (di->MeshBuilding || vp.Pos.Z >= rover->top.plane->ZatPoint(vp.Pos)) { SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG)); Colormap.FadeColor = frontsector->Colormap.FadeColor; diff --git a/src/rendering/hwrenderer/scene/hw_meshcache.cpp b/src/rendering/hwrenderer/scene/hw_meshcache.cpp index 5c63f41659..4340da2b62 100644 --- a/src/rendering/hwrenderer/scene/hw_meshcache.cpp +++ b/src/rendering/hwrenderer/scene/hw_meshcache.cpp @@ -3,35 +3,100 @@ #include "hw_drawinfo.h" #include "hw_drawstructs.h" #include "hw_mesh.h" +#include "hw_fakeflat.h" +#include "hw_vertexbuilder.h" #include "g_levellocals.h" +#include EXTERN_CVAR(Bool, gl_texture) EXTERN_CVAR(Float, gl_mask_threshold) HWMeshCache meshcache; +void HWMeshCache::Clear() +{ + Sectors.Reset(); + nextRefresh = 0; +} + void HWMeshCache::Update(FRenderViewpoint& vp) { auto level = vp.ViewLevel; unsigned int count = level->sectors.Size(); Sectors.Resize(count); + + // Look for changes for (unsigned int i = 0; i < count; i++) { auto sector = &level->sectors[i]; - if (Sectors[i].Sector != sector) // Note: this is just a stupid way to detect we changed map. What is the proper way? + auto cacheitem = &Sectors[i]; + if (cacheitem->Floorplane != sector->floorplane || cacheitem->Ceilingplane != sector->ceilingplane) // Sector height changes { - Sectors[i].Sector = sector; - Sectors[i].Update(vp); + cacheitem->NeedsUpdate = true; + for (line_t* line : sector->Lines) + { + sector_t* backsector = (line->frontsector == sector) ? line->backsector : line->frontsector; + if (backsector) + { + Sectors[backsector->Index()].NeedsUpdate = true; + } + } + } + } + + // Refresh 10 sectors per frame. Shouldn't be needed but for some reason some initial flats are black!! + for (int i = 0; i < 10; i++) + { + if (nextRefresh < count) + { + Sectors[nextRefresh].NeedsUpdate = true; + } + if (count > 0) + nextRefresh = (nextRefresh + 1) % count; + } + + // Update changed sectors + for (unsigned int i = 0; i < count; i++) + { + auto sector = &level->sectors[i]; + auto cacheitem = &Sectors[i]; + if (cacheitem->NeedsUpdate) + { + cacheitem->NeedsUpdate = false; + cacheitem->Sector = sector; + cacheitem->Floorplane = sector->floorplane; + cacheitem->Ceilingplane = sector->ceilingplane; + cacheitem->Update(vp); } } } void HWCachedSector::Update(FRenderViewpoint& vp) { + Opaque.reset(); + Translucent.reset(); + TranslucentDepthBiased.reset(); + HWDrawInfo* di = HWDrawInfo::StartDrawInfo(vp.ViewLevel, nullptr, vp, nullptr); di->MeshBuilding = true; - // Add all the walls to the draw lists + // Add to the draw lists + + CheckUpdate(screen->mVertexData, Sector); + std::unordered_set seenSections; + for (int i = 0, count = Sector->subsectorcount; i < count; i++) + { + subsector_t* subsector = Sector->subsectors[i]; + if (seenSections.find(subsector->section) == seenSections.end()) + { + seenSections.insert(subsector->section); + + HWFlat flat; + flat.section = subsector->section; + sector_t* front = hw_FakeFlat(subsector->render_sector, area_default, false); + flat.ProcessSector(di, front); + } + } for (line_t* line : Sector->Lines) { diff --git a/src/rendering/hwrenderer/scene/hw_meshcache.h b/src/rendering/hwrenderer/scene/hw_meshcache.h index 868ef686c3..08d793f668 100644 --- a/src/rendering/hwrenderer/scene/hw_meshcache.h +++ b/src/rendering/hwrenderer/scene/hw_meshcache.h @@ -8,7 +8,11 @@ struct FRenderViewpoint; class HWCachedSector { public: + bool NeedsUpdate = true; + sector_t* Sector = nullptr; + secplane_t Floorplane; + secplane_t Ceilingplane; std::unique_ptr Opaque; std::unique_ptr Translucent; @@ -20,11 +24,13 @@ public: class HWMeshCache { public: + void Clear(); void Update(FRenderViewpoint& vp); TArray Sectors; private: + unsigned int nextRefresh = 0; }; extern HWMeshCache meshcache;