From 8d10617762d7d0e92e44b4dd493c79cd1c4d3b20 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 31 May 2025 23:57:38 +0200 Subject: [PATCH] Disable skyhack for level mesh and fix frustum test against skies --- src/rendering/hwrenderer/doom_levelmesh.cpp | 59 +++++++++++++++---- src/rendering/hwrenderer/doom_levelmesh.h | 3 +- .../hwrenderer/scene/hw_drawinfo.cpp | 56 +++++++++++++++--- src/rendering/hwrenderer/scene/hw_drawinfo.h | 2 + .../hwrenderer/scene/hw_fakeflat.cpp | 21 +++++++ 5 files changed, 118 insertions(+), 23 deletions(-) diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 8bce30fab..f801ff45c 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -10,6 +10,7 @@ #include "hw_renderstate.h" #include "hw_vertexbuilder.h" #include "hw_dynlightdata.h" +#include "hwrenderer/scene/hw_fakeflat.h" #include "hwrenderer/scene/hw_lighting.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawinfo.h" @@ -329,23 +330,33 @@ void DoomLevelMesh::AddSectorsToDrawLists(const TArray& sectors, LevelMeshD } } -void DoomLevelMesh::AddSidesToDrawLists(const TArray& sides, LevelMeshDrawLists& lists, HWDrawInfo* di) +void DoomLevelMesh::AddSidesToDrawLists(const TArray& sides, LevelMeshDrawLists& lists, HWDrawInfo* di, FRenderState& state) { for (int sideIndex : sides) { - for (const DrawRangeInfo& di : Sides[sideIndex].DrawRanges) + if (!Sides[sideIndex].NeedsImmediateRendering) { - lists.Add(di.DrawType, di.PipelineID, { di.IndexStart, di.IndexStart + di.IndexCount }); - } + for (const DrawRangeInfo& di : Sides[sideIndex].DrawRanges) + { + lists.Add(di.DrawType, di.PipelineID, { di.IndexStart, di.IndexStart + di.IndexCount }); + } - for (const HWMissing& missing : Sides[sideIndex].MissingUpper) - { - di->AddUpperMissingTexture(missing.side, missing.sub, missing.plane); - } + for (const HWMissing& missing : Sides[sideIndex].MissingUpper) + { + di->AddUpperMissingTexture(missing.side, missing.sub, missing.plane); + } - for (const HWMissing& missing : Sides[sideIndex].MissingLower) + for (const HWMissing& missing : Sides[sideIndex].MissingLower) + { + di->AddLowerMissingTexture(missing.side, missing.sub, missing.plane); + } + } + else { - di->AddLowerMissingTexture(missing.side, missing.sub, missing.plane); + // To do: is it good enough to just grab the first seg here? + side_t* side = &di->Level->sides[sideIndex]; + seg_t* seg = side->segs[0]; + di->ProcessSeg(seg, state); } } } @@ -673,6 +684,8 @@ void DoomLevelMesh::FreeSide(FLevelLocals& doomMap, unsigned int sideIndex) Sides[sideIndex].MissingUpper.Clear(); Sides[sideIndex].MissingLower.Clear(); Sides[sideIndex].Decals.Clear(); + + Sides[sideIndex].NeedsImmediateRendering = false; } void DoomLevelMesh::FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex) @@ -1088,6 +1101,29 @@ void DoomLevelMesh::CreateSide(FLevelLocals& doomMap, unsigned int sideIndex) state.SetDepthFunc(DF_LEqual); // DrawDecals(state, Decals[0]); + // These things aren't working properly with the level mesh. + bool incompatible = false; + for (const HWWall& wall : result.opaque) + if ((wall.flags & HWWall::HWF_SKYHACK) != 0) + incompatible = true; + for (const HWWall& wall : result.masked) + if ((wall.flags & HWWall::HWF_SKYHACK) != 0) + incompatible = true; + for (const HWWall& wall : result.maskedOffset) + if ((wall.flags & HWWall::HWF_SKYHACK) != 0) + incompatible = true; + + if (result.translucent.size() != 0 || result.translucentBorder.size() != 0 || incompatible) + { + // For things that HWWall doesn't do correctly when drawn into the level mesh for one reason or another. + sideBlock.NeedsImmediateRendering = true; + } + else + { + for (const HWWall& portal : result.portals) + sideBlock.WallPortals.Push(portal); + } + /* // final pass: translucent stuff state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); @@ -1102,9 +1138,6 @@ void DoomLevelMesh::CreateSide(FLevelLocals& doomMap, unsigned int sideIndex) state.SetRenderStyle(STYLE_Normal); */ - for (const HWWall& portal : result.portals) - sideBlock.WallPortals.Push(portal); - for (const HWMissing& missing : result.upper) sideBlock.MissingUpper.Push(missing); diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 28f2945c4..763b93808 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -84,6 +84,7 @@ struct SideSurfaceBlock TArray MissingLower; TArray Decals; bool InSideDecalsList = false; + bool NeedsImmediateRendering = false; TArray DrawRanges; SurfaceUpdateType UpdateType = SurfaceUpdateType::None; LightListAllocInfo Lights; @@ -152,7 +153,7 @@ public: void ProcessDecals(HWDrawInfo* drawinfo, FRenderState& state); void AddSectorsToDrawLists(const TArray& sectors, LevelMeshDrawLists& lists); - void AddSidesToDrawLists(const TArray& sides, LevelMeshDrawLists& lists, HWDrawInfo* di); + void AddSidesToDrawLists(const TArray& sides, LevelMeshDrawLists& lists, HWDrawInfo* di, FRenderState& state); TArray& GetSidePortals(int sideIndex); diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 22ac64dfe..fca3caee8 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -447,12 +447,13 @@ void HWDrawInfo::RenderPVS(bool drawpsprites, FRenderState& state) } else { - // Anything outside the BSP using this? viewx = FLOAT2FIXED(Viewpoint.Pos.X); viewy = FLOAT2FIXED(Viewpoint.Pos.Y); multithread = false; uselevelmesh = true; + validcount++; // used for processing sidedefs only once by the renderer. + Bsp.Clock(); ClipWall.Clock(); @@ -504,6 +505,14 @@ void HWDrawInfo::RenderPVS(bool drawpsprites, FRenderState& state) } } + if (gl_levelmesh) + level.levelMesh->CurFrameStats.Portals++; + + SeenFlatsDrawLists.Clear(); + SeenSidesDrawLists.Clear(); + level.levelMesh->AddSectorsToDrawLists(SeenSectors.Get(), SeenFlatsDrawLists); + level.levelMesh->AddSidesToDrawLists(SeenSides.Get(), SeenSidesDrawLists, this, state); + if (gl_render_things) { for (int subIndex : SeenSubsectors.Get()) @@ -537,6 +546,43 @@ void HWDrawInfo::RenderPVS(bool drawpsprites, FRenderState& state) } } +void HWDrawInfo::ProcessSeg(seg_t* seg, FRenderState& state) +{ + subsector_t* sub = seg->Subsector; + sector_t* front, * back; + front = hw_FakeFlat(drawctx, sub->sector, in_area, false); + auto backsector = seg->backsector; + if (!backsector && seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0]) // For one-sided portals use the portal's destination sector as backsector. + { + auto portal = seg->linedef->getPortal(); + backsector = portal->mDestination->frontsector; + back = hw_FakeFlat(drawctx, backsector, in_area, true); + if (front->floorplane.isSlope() || front->ceilingplane.isSlope() || back->floorplane.isSlope() || back->ceilingplane.isSlope()) + { + // Having a one-sided portal like this with slopes is too messy so let's ignore that case. + back = nullptr; + } + } + else if (backsector) + { + if (front->sectornum == backsector->sectornum || (seg->sidedef->Flags & WALLF_POLYOBJ)) + { + back = front; + } + else + { + back = hw_FakeFlat(drawctx, backsector, in_area, true); + } + } + else back = nullptr; + + HWMeshHelper result; + HWWallDispatcher disp(this); + HWWall wall; + wall.sub = sub; + wall.Process(&disp, state, seg, front, back); +} + //----------------------------------------------------------------------------- // // CreateScene @@ -569,14 +615,6 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state) RenderPVS(drawpsprites, state); - if (gl_levelmesh) - level.levelMesh->CurFrameStats.Portals++; - - SeenFlatsDrawLists.Clear(); - SeenSidesDrawLists.Clear(); - level.levelMesh->AddSectorsToDrawLists(SeenSectors.Get(), SeenFlatsDrawLists); - level.levelMesh->AddSidesToDrawLists(SeenSides.Get(), SeenSidesDrawLists, this); - // And now the crappy hacks that have to be done to avoid rendering anomalies. // These cannot be multithreaded when the time comes because all these depend // on the global 'validcount' variable. diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index c25c3e9ef..84cbcfff0 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -316,6 +316,8 @@ public: } } + void ProcessSeg(seg_t* seg, FRenderState& state); + HWPortal * FindPortal(const void * src); void RenderBSPNode(void *node, FRenderState& state); void RenderOrthoNoFog(FRenderState& state); diff --git a/src/rendering/hwrenderer/scene/hw_fakeflat.cpp b/src/rendering/hwrenderer/scene/hw_fakeflat.cpp index 3d0015e0e..4cd41bc00 100644 --- a/src/rendering/hwrenderer/scene/hw_fakeflat.cpp +++ b/src/rendering/hwrenderer/scene/hw_fakeflat.cpp @@ -158,6 +158,27 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto if (frustum) { + if (frontsector->GetTexture(sector_t::ceiling) == skyflatnum) + { + fs_ceilingheight1 = 32768.0; + fs_ceilingheight2 = 32768.0; + } + if (frontsector->GetTexture(sector_t::floor) == skyflatnum) + { + fs_floorheight1 = -32768.0; + fs_floorheight1 = -32768.0; + } + if (backsector->GetTexture(sector_t::ceiling) == skyflatnum) + { + bs_ceilingheight1 = 32768.0; + bs_ceilingheight2 = 32768.0; + } + if (backsector->GetTexture(sector_t::floor) == skyflatnum) + { + bs_floorheight1 = -32768.0; + bs_floorheight1 = -32768.0; + } + // Is the line visible by the camera's clip frustum? DVector3 p0(linedef->v1->fX(), std::min(bs_ceilingheight1, fs_ceilingheight1), linedef->v1->fY()); DVector3 p1(linedef->v2->fX(), std::min(bs_ceilingheight2, fs_ceilingheight2), linedef->v2->fY());