From 9f6091519f62ffdb9cd773bab48249dbf1945c80 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 14 Nov 2018 23:30:46 +0100 Subject: [PATCH] - changed the stencil cap drawer to only cover the area which is actually used by the portal. This will now both exclude floor caps when only ceiling elements are used and everything outside the bounding box of active portal lines. Hopefully this is enough to fix the issues with portal caps but of course it is not foolproof if someone just makes the right setup. --- src/hwrenderer/scene/hw_drawstructs.h | 2 +- src/hwrenderer/scene/hw_portal.cpp | 31 ++++++++++++++++++++++++-- src/hwrenderer/scene/hw_portal.h | 6 ++++- src/hwrenderer/scene/hw_sky.cpp | 6 ++--- src/hwrenderer/scene/hw_walls.cpp | 20 ++++++++++------- src/r_data/r_sections.cpp | 10 ++++----- src/r_data/r_sections.h | 32 +++++++++++++++++++++++---- 7 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index d500e67957..ae89d65de9 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -201,7 +201,7 @@ public: //private: void PutWall(HWDrawInfo *di, bool translucent); - void PutPortal(HWDrawInfo *di, int ptype); + void PutPortal(HWDrawInfo *di, int ptype, int plane); void CheckTexturePosition(FTexCoordInfo *tci); void Put3DWall(HWDrawInfo *di, lightlist_t * lightlist, bool translucent); diff --git a/src/hwrenderer/scene/hw_portal.cpp b/src/hwrenderer/scene/hw_portal.cpp index d951a7e64e..9cb35c696c 100644 --- a/src/hwrenderer/scene/hw_portal.cpp +++ b/src/hwrenderer/scene/hw_portal.cpp @@ -140,6 +140,14 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di best = p; bestindex = i; } + + // If the portal area contains the current camera viewpoint, let's always use it because it's likely to give the largest area. + if (p->boundingBox.contains(outer_di->Viewpoint.Pos)) + { + best = p; + bestindex = i; + break; + } } } @@ -187,8 +195,27 @@ void HWPortal::DrawPortalStencil(FRenderState &state, int pass) { // The cap's depth handling needs special treatment so that it won't block further portal caps. if (pass == STP_DepthRestore) state.SetDepthRange(1, 1); - state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILTOP_INDEX, 4, false); - state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILBOTTOM_INDEX, 4, false); + + if (planesused & (1 << sector_t::floor)) + { + auto verts = screen->mVertexData->AllocVertices(4); + auto ptr = verts.first; + ptr[0].Set((float)boundingBox.left, -32767.f, (float)boundingBox.top, 0, 0); + ptr[1].Set((float)boundingBox.right, -32767.f, (float)boundingBox.top, 0, 0); + ptr[2].Set((float)boundingBox.left, -32767.f, (float)boundingBox.bottom, 0, 0); + ptr[3].Set((float)boundingBox.right, -32767.f, (float)boundingBox.bottom, 0, 0); + state.Draw(DT_TriangleStrip, verts.second, 4, false); + } + if (planesused & (1 << sector_t::ceiling)) + { + auto verts = screen->mVertexData->AllocVertices(4); + auto ptr = verts.first; + ptr[0].Set((float)boundingBox.left, 32767.f, (float)boundingBox.top, 0, 0); + ptr[1].Set((float)boundingBox.right, 32767.f, (float)boundingBox.top, 0, 0); + ptr[2].Set((float)boundingBox.left, 32767.f, (float)boundingBox.bottom, 0, 0); + ptr[3].Set((float)boundingBox.right, 32767.f, (float)boundingBox.bottom, 0, 0); + state.Draw(DT_TriangleStrip, verts.second, 4, false); + } if (pass == STP_DepthRestore) state.SetDepthRange(0, 1); } } diff --git a/src/hwrenderer/scene/hw_portal.h b/src/hwrenderer/scene/hw_portal.h index 42d71434d7..f9d9e243c6 100644 --- a/src/hwrenderer/scene/hw_portal.h +++ b/src/hwrenderer/scene/hw_portal.h @@ -61,8 +61,10 @@ class HWPortal public: FPortalSceneState * mState; TArray lines; + BoundingRect boundingBox; + int planesused = 0; - HWPortal(FPortalSceneState *s, bool local = false) : mState(s) + HWPortal(FPortalSceneState *s, bool local = false) : mState(s), boundingBox(false) { } virtual ~HWPortal() {} @@ -83,6 +85,8 @@ public: void AddLine(GLWall * l) { lines.Push(*l); + boundingBox.addVertex(l->glseg.x1, l->glseg.y1); + boundingBox.addVertex(l->glseg.x2, l->glseg.y2); } diff --git a/src/hwrenderer/scene/hw_sky.cpp b/src/hwrenderer/scene/hw_sky.cpp index 57eeb0eee3..695321312a 100644 --- a/src/hwrenderer/scene/hw_sky.cpp +++ b/src/hwrenderer/scene/hw_sky.cpp @@ -122,7 +122,7 @@ void GLWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref skyinfo.init(sector->sky, Colormap.FadeColor); ptype = PORTALTYPE_SKY; sky = &skyinfo; - PutPortal(di, ptype); + PutPortal(di, ptype, plane); } else if (sportal != nullptr) { @@ -162,7 +162,7 @@ void GLWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref } if (ptype != -1) { - PutPortal(di, ptype); + PutPortal(di, ptype, plane); } } @@ -197,7 +197,7 @@ void GLWall::SkyLine(HWDrawInfo *di, sector_t *fs, line_t *line) ztop[1] = zceil[1]; zbottom[0] = zfloor[0]; zbottom[1] = zfloor[1]; - PutPortal(di, ptype); + PutPortal(di, ptype, -1); } diff --git a/src/hwrenderer/scene/hw_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index cffecb0af5..70ca0f6335 100644 --- a/src/hwrenderer/scene/hw_walls.cpp +++ b/src/hwrenderer/scene/hw_walls.cpp @@ -483,10 +483,10 @@ void GLWall::PutWall(HWDrawInfo *di, bool translucent) // //========================================================================== -void GLWall::PutPortal(HWDrawInfo *di, int ptype) +void GLWall::PutPortal(HWDrawInfo *di, int ptype, int plane) { auto pstate = screen->mPortalState; - HWPortal * portal; + HWPortal * portal = nullptr; MakeVertices(di, false); switch (ptype) @@ -532,7 +532,6 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) case PORTALTYPE_PLANEMIRROR: if (pstate->PlaneMirrorMode * planemirror->fC() <= 0) { - //@sync-portal planemirror = pstate->UniquePlaneMirrors.Get(planemirror); portal = di->FindPortal(planemirror); if (!portal) @@ -588,6 +587,11 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) break; } vertcount = 0; + + if (plane != -1 && portal) + { + portal->planesused |= (1<isFullbrightScene()) hi.colormap.Clear(); horizon = &hi; - PutPortal(di, PORTALTYPE_HORIZON); + PutPortal(di, PORTALTYPE_HORIZON, -1); } ztop[1] = ztop[0] = zbottom[0]; } @@ -878,7 +882,7 @@ bool GLWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1, if (di->isFullbrightScene()) hi.colormap.Clear(); horizon = &hi; - PutPortal(di, PORTALTYPE_HORIZON); + PutPortal(di, PORTALTYPE_HORIZON, -1); } } return true; @@ -1135,7 +1139,7 @@ void GLWall::DoTexture(HWDrawInfo *di, int _type,seg_t * seg, int peg, if (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && gl_mirrors) { - PutPortal(di, PORTALTYPE_MIRROR); + PutPortal(di, PORTALTYPE_MIRROR, -1); } else { @@ -1970,7 +1974,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ ztop[1] = zceil[1]; zbottom[0] = zfloor[0]; zbottom[1] = zfloor[1]; - PutPortal(di, PORTALTYPE_LINETOLINE); + PutPortal(di, PORTALTYPE_LINETOLINE, -1); } else if (seg->linedef->GetTransferredPortal()) { @@ -2077,7 +2081,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ ztop[1] = bch2; zbottom[0] = bfh1; zbottom[1] = bfh2; - PutPortal(di, PORTALTYPE_LINETOLINE); + PutPortal(di, PORTALTYPE_LINETOLINE, -1); } else if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size()) { diff --git a/src/r_data/r_sections.cpp b/src/r_data/r_sections.cpp index 74b89f9a59..8f10f2fb33 100644 --- a/src/r_data/r_sections.cpp +++ b/src/r_data/r_sections.cpp @@ -495,9 +495,9 @@ public: auto §ion = sections[i]; auto &work = triangles[i]; - BoundingRect bounds = { 1e32, 1e32, -1e32, -1e32 }; - BoundingRect loopBounds = { 1e32, 1e32, -1e32, -1e32 }; - BoundingRect outermostBounds = { 1e32, 1e32, -1e32, -1e32 }; + BoundingRect bounds(false); + BoundingRect loopBounds(false); + BoundingRect outermostBounds(false); unsigned outermoststart = ~0u; unsigned loopstart = 0; bool ispolyorg = false; @@ -519,7 +519,7 @@ public: outermoststart = loopstart; loopstart = i + 1; } - loopBounds = { 1e32, 1e32, -1e32, -1e32 }; + loopBounds.setEmpty(); } } work.boundingLoopStart = outermoststart; @@ -716,7 +716,7 @@ public: dest.subsectors.Set(&output.allSubsectors[numsubsectors], group.subsectors.Size()); dest.vertexindex = -1; dest.vertexcount = 0; - dest.bounds = {1e32, 1e32, -1e32, -1e32}; + dest.bounds.setEmpty(); numsegments += group.segments.Size(); if (output.firstSectionForSectorPtr[dest.sector->Index()] == -1) diff --git a/src/r_data/r_sections.h b/src/r_data/r_sections.h index 96ab3c2500..35f61cb7cd 100644 --- a/src/r_data/r_sections.h +++ b/src/r_data/r_sections.h @@ -25,12 +25,35 @@ struct BoundingRect { double left, top, right, bottom; - bool contains(const BoundingRect & other) + BoundingRect() = default; + BoundingRect(bool) + { + setEmpty(); + } + + void setEmpty() + { + left = top = 1e38; + bottom = right = -1e38; + } + + bool contains(const BoundingRect & other) const { return left <= other.left && top <= other.top && right >= other.right && bottom >= other.bottom; } - bool intersects(const BoundingRect & other) + bool contains(double x, double y) const + { + return left <= x && top <= y && right >= x && bottom >= y; + } + + template + bool contains(const T &vec) const + { + return left <= vec.X && top <= vec.Y && right >= vec.X && bottom >= vec.Y; + } + + bool intersects(const BoundingRect & other) const { return !(other.left > right || other.right < left || @@ -46,7 +69,7 @@ struct BoundingRect if (other.bottom > bottom) bottom = other.bottom; } - double distanceTo(const BoundingRect &other) + double distanceTo(const BoundingRect &other) const { if (intersects(other)) return 0; return std::max(std::min(fabs(left - other.right), fabs(right - other.left)), @@ -61,10 +84,11 @@ struct BoundingRect if (y > bottom) bottom = y; } - bool operator == (const BoundingRect &other) + bool operator == (const BoundingRect &other) const { return left == other.left && top == other.top && right == other.right && bottom == other.bottom; } + };