diff --git a/src/r_poly_cull.cpp b/src/r_poly_cull.cpp index 9ee71c28a8..a688c26444 100644 --- a/src/r_poly_cull.cpp +++ b/src/r_poly_cull.cpp @@ -93,7 +93,7 @@ void PolyCull::CullSubsector(subsector_t *sub) continue; int sx1, sx2; - if (GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2)) + if (GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2) == LineSegmentRange::HasSegment) { MarkSegmentCulled(sx1, sx2); } @@ -200,7 +200,8 @@ bool PolyCull::CheckBBox(float *bspcoord) float x2 = bspcoord[lines[i][2]]; float y2 = bspcoord[lines[i][3]]; int sx1, sx2; - if (GetSegmentRangeForLine(x1, y1, x2, y2, sx1, sx2)) + LineSegmentRange result = GetSegmentRangeForLine(x1, y1, x2, y2, sx1, sx2); + if (result == LineSegmentRange::HasSegment) { if (foundline) { @@ -214,6 +215,10 @@ bool PolyCull::CheckBBox(float *bspcoord) foundline = true; } } + else if (result == LineSegmentRange::AlwaysVisible) + { + return true; + } } if (!foundline) return false; @@ -221,13 +226,14 @@ bool PolyCull::CheckBBox(float *bspcoord) return !IsSegmentCulled(minsx1, maxsx2); } -bool PolyCull::GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const +LineSegmentRange PolyCull::GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const { double znear = 5.0; + double updownnear = -400.0; // Cull if entirely behind the portal clip plane (tbd: should we clip the segment?) if (Vec4f::dot(PortalClipPlane, Vec4f((float)x1, (float)y1, 0.0f, 1.0f)) < 0.0f && Vec4f::dot(PortalClipPlane, Vec4f((float)x2, (float)y2, 0.0f, 1.0f)) < 0.0f) - return false; + return LineSegmentRange::NotVisible; // Transform to 2D view space: x1 = x1 - ViewPos.X; @@ -239,8 +245,13 @@ bool PolyCull::GetSegmentRangeForLine(double x1, double y1, double x2, double y2 double ry1 = x1 * ViewCos + y1 * ViewSin; double ry2 = x2 * ViewCos + y2 * ViewSin; + // Is it potentially visible when looking straight up or down? + if (!(ry1 < updownnear && ry2 < updownnear) && !(ry1 > znear && ry2 > znear)) + return LineSegmentRange::AlwaysVisible; + // Cull if line is entirely behind view - if (ry1 < znear && ry2 < znear) return false; + if (ry1 < znear && ry2 < znear) + return LineSegmentRange::NotVisible; // Clip line, if needed double t1 = 0.0f, t2 = 1.0f; @@ -265,5 +276,5 @@ bool PolyCull::GetSegmentRangeForLine(double x1, double y1, double x2, double y2 if (sx1 > sx2) std::swap(sx1, sx2); - return sx1 != sx2; + return (sx1 != sx2) ? LineSegmentRange::HasSegment : LineSegmentRange::AlwaysVisible; } diff --git a/src/r_poly_cull.h b/src/r_poly_cull.h index f1fe56ed53..fe3cd9f5d3 100644 --- a/src/r_poly_cull.h +++ b/src/r_poly_cull.h @@ -25,12 +25,19 @@ #include "r_poly_triangle.h" #include "r_poly_intersection.h" +enum class LineSegmentRange +{ + NotVisible, + HasSegment, + AlwaysVisible +}; + class PolyCull { public: void CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane); - bool GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const; + LineSegmentRange GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const; void MarkSegmentCulled(int x1, int x2); bool IsSegmentCulled(int x1, int x2) const; diff --git a/src/r_poly_portal.cpp b/src/r_poly_portal.cpp index 1047164cb4..b5553665c2 100644 --- a/src/r_poly_portal.cpp +++ b/src/r_poly_portal.cpp @@ -174,12 +174,12 @@ void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *front // Cull wall if not visible int sx1, sx2; - bool hasSegmentRange = Cull.GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2); - if (!hasSegmentRange || Cull.IsSegmentCulled(sx1, sx2)) + LineSegmentRange segmentRange = Cull.GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2); + if (segmentRange == LineSegmentRange::NotVisible || (segmentRange == LineSegmentRange::HasSegment && Cull.IsSegmentCulled(sx1, sx2))) return; // Tell automap we saw this - if (!swrenderer::r_dontmaplines && line->linedef) + if (!swrenderer::r_dontmaplines && line->linedef && segmentRange != LineSegmentRange::AlwaysVisible) { line->linedef->flags |= ML_MAPPED; sub->flags |= SSECF_DRAWN; @@ -201,7 +201,7 @@ void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *front // Render wall, and update culling info if its an occlusion blocker if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals)) { - if (hasSegmentRange) + if (segmentRange == LineSegmentRange::HasSegment) Cull.MarkSegmentCulled(sx1, sx2); } }