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; } + };