diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index a0a0483b3..2da2dbcf9 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -159,8 +159,6 @@ void PolyRenderer::ClearBuffers() PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0); PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight()); NextStencilValue = 0; - SeenLinePortals.clear(); - SeenMirrors.clear(); } void PolyRenderer::SetSceneViewport() @@ -216,13 +214,3 @@ void PolyRenderer::SetupPerspectiveMatrix() WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; } - -bool PolyRenderer::InsertSeenLinePortal(FLinePortal *portal) -{ - return SeenLinePortals.insert(portal).second; -} - -bool PolyRenderer::InsertSeenMirror(line_t *mirrorLine) -{ - return SeenMirrors.insert(mirrorLine).second; -} diff --git a/src/polyrenderer/poly_renderer.h b/src/polyrenderer/poly_renderer.h index ead3c8eac..efd1bbf67 100644 --- a/src/polyrenderer/poly_renderer.h +++ b/src/polyrenderer/poly_renderer.h @@ -52,9 +52,6 @@ public: uint32_t GetNextStencilValue() { uint32_t value = NextStencilValue; NextStencilValue += 2; return value; } - bool InsertSeenLinePortal(FLinePortal *portal); - bool InsertSeenMirror(line_t *mirrorLine); - bool DontMapLines = false; RenderMemory FrameMemory; @@ -75,7 +72,4 @@ private: PolySkyDome Skydome; RenderPolyPlayerSprites PlayerSprites; uint32_t NextStencilValue = 0; - - std::set SeenLinePortals; - std::set SeenMirrors; }; diff --git a/src/polyrenderer/scene/poly_cull.cpp b/src/polyrenderer/scene/poly_cull.cpp index 623b6e9df..8f19cb901 100644 --- a/src/polyrenderer/scene/poly_cull.cpp +++ b/src/polyrenderer/scene/poly_cull.cpp @@ -70,6 +70,20 @@ void PolyCull::CullNode(void *node) void PolyCull::CullSubsector(subsector_t *sub) { + // Check if subsector is clipped entirely by the portal clip plane + bool visible = false; + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + if (PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D > 0.0) + { + visible = true; + break; + } + } + if (!visible) + return; + // Update sky heights for the scene if (!FirstSkyHeight) { @@ -98,6 +112,13 @@ void PolyCull::CullSubsector(subsector_t *sub) if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0) continue; + // Skip line if entirely behind portal clipping plane + if ((PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D <= 0.0) || + (PortalClipPlane.A * line->v2->fX() + PortalClipPlane.B * line->v2->fY() + PortalClipPlane.D <= 0.0)) + { + continue; + } + angle_t angle1, angle2; if (GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2)) { @@ -119,11 +140,11 @@ void PolyCull::InvertSegments() angle_t cur = 0; for (const auto &segment : TempInvertSolidSegments) { - if (segment.Start != 0 || segment.End != ANGLE_MAX) + if (cur < segment.Start) MarkSegmentCulled(cur, segment.Start - 1); cur = segment.End + 1; } - if (cur != 0) + if (cur < ANGLE_MAX) MarkSegmentCulled(cur, ANGLE_MAX); } @@ -241,32 +262,6 @@ bool PolyCull::CheckBBox(float *bspcoord) bool PolyCull::GetAnglesForLine(double x1, double y1, double x2, double y2, angle_t &angle1, angle_t &angle2) const { -#if 0 - // Clip line to the portal clip plane - float distance1 = Vec4f::dot(PortalClipPlane, Vec4f((float)x1, (float)y1, 0.0f, 1.0f)); - float distance2 = Vec4f::dot(PortalClipPlane, Vec4f((float)x2, (float)y2, 0.0f, 1.0f)); - if (distance1 < 0.0f && distance2 < 0.0f) - { - return false; - } - else if (distance1 < 0.0f || distance2 < 0.0f) - { - double t1 = 0.0f, t2 = 1.0f; - if (distance1 < 0.0f) - t1 = clamp(distance1 / (distance1 - distance2), 0.0f, 1.0f); - else - t2 = clamp(distance2 / (distance1 - distance2), 0.0f, 1.0f); - double nx1 = x1 * (1.0 - t1) + x2 * t1; - double ny1 = y1 * (1.0 - t1) + y2 * t1; - double nx2 = x1 * (1.0 - t2) + x2 * t2; - double ny2 = y1 * (1.0 - t2) + y2 * t2; - x1 = nx1; - x2 = nx2; - y1 = ny1; - y2 = ny2; - } -#endif - angle2 = PointToPseudoAngle(x1, y1); angle1 = PointToPseudoAngle(x2, y2); return !IsSegmentCulled(angle1, angle2); diff --git a/src/polyrenderer/scene/poly_cull.h b/src/polyrenderer/scene/poly_cull.h index 64e4d5739..0af3b22f9 100644 --- a/src/polyrenderer/scene/poly_cull.h +++ b/src/polyrenderer/scene/poly_cull.h @@ -40,6 +40,8 @@ public: double MaxCeilingHeight = 0.0; double MinFloorHeight = 0.0; + static angle_t PointToPseudoAngle(double x, double y); + private: struct SolidSegment { @@ -62,6 +64,5 @@ private: PolyClipPlane PortalClipPlane; - static angle_t PointToPseudoAngle(double x, double y); static angle_t AngleToPseudo(angle_t ang); }; diff --git a/src/polyrenderer/scene/poly_portal.cpp b/src/polyrenderer/scene/poly_portal.cpp index 0e0ffbf38..ff529895f 100644 --- a/src/polyrenderer/scene/poly_portal.cpp +++ b/src/polyrenderer/scene/poly_portal.cpp @@ -43,44 +43,10 @@ void PolyDrawSectorPortal::Render(int portalDepth) if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE) return; - const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; - - PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f); - if (Portal->mType != PORTS_SKYVIEWPOINT) - { - float minHeight; - float maxHeight; - bool first = true; - for (const auto &range : Shape) - { - for (int i = 0; i < range.Count; i++) - { - if (first) - { - minHeight = range.Vertices[i].z; - maxHeight = range.Vertices[i].z; - first = false; - } - else - { - minHeight = MIN(minHeight, range.Vertices[i].z); - maxHeight = MAX(maxHeight, range.Vertices[i].z); - } - } - } - - if (!first && minHeight > viewpoint.Pos.Z) - { - portalPlane = PolyClipPlane(0.0f, 0.0f, 1.0f, -minHeight); - } - else if (!first && maxHeight < viewpoint.Pos.Z) - { - portalPlane = PolyClipPlane(0.0f, 0.0f, -1.0f, maxHeight); - } - } - SaveGlobals(); + const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; + // To do: get this information from PolyRenderer instead of duplicating the code.. const auto &viewwindow = PolyRenderer::Instance()->Viewwindow; double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians(); @@ -100,6 +66,7 @@ void PolyDrawSectorPortal::Render(int portalDepth) TriMatrix::translate((float)-viewpoint.Pos.X, (float)-viewpoint.Pos.Y, (float)-viewpoint.Pos.Z); TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; + PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f); RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue); RenderPortal.SetPortalSegments(Segments); RenderPortal.Render(portalDepth); @@ -211,14 +178,29 @@ void PolyDrawLinePortal::Render(int portalDepth) worldToView = TriMatrix::scale(-1.0f, 1.0f, 1.0f) * worldToView; TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; - // Calculate plane clipping + // Find portal destination line and make sure it faces the right way line_t *clipLine = Portal ? Portal->mDestination : Mirror; - DVector2 planePos = clipLine->v1->fPos(); - DVector2 planeNormal = (clipLine->v2->fPos() - clipLine->v1->fPos()).Rotated90CW(); + DVector2 pt1 = clipLine->v1->fPos() - viewpoint.Pos; + DVector2 pt2 = clipLine->v2->fPos() - viewpoint.Pos; + bool backfacing = (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0); + vertex_t *v1 = backfacing ? clipLine->v1 : clipLine->v2; + vertex_t *v2 = backfacing ? clipLine->v2 : clipLine->v1; + + // Calculate plane clipping + DVector2 planePos = v1->fPos(); + DVector2 planeNormal = (v2->fPos() - v1->fPos()).Rotated90CW(); planeNormal.MakeUnit(); double planeD = -(planeNormal | (planePos + planeNormal * 0.001)); PolyClipPlane portalPlane((float)planeNormal.X, (float)planeNormal.Y, (float)0.0f, (float)planeD); + // Cull everything outside the portal line + // To do: this doesn't work for some strange reason.. + /*angle_t angle1 = PolyCull::PointToPseudoAngle(v1->fX(), v1->fY()); + angle_t angle2 = PolyCull::PointToPseudoAngle(v2->fX(), v2->fY()); + Segments.clear(); + Segments.push_back({ angle1, angle2 });*/ + + RenderPortal.LastPortalLine = clipLine; RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue); RenderPortal.SetPortalSegments(Segments); RenderPortal.Render(portalDepth); @@ -296,6 +278,9 @@ void PolyDrawLinePortal::SaveGlobals() P_TranslatePortalXY(src, viewpoint.Path[0].X, viewpoint.Path[0].Y); P_TranslatePortalXY(src, viewpoint.Path[1].X, viewpoint.Path[1].Y); + if (viewpoint.camera) + viewpoint.camera->renderflags &= ~RF_INVISIBLE; + if (!viewpoint.showviewer && viewpoint.camera && P_PointOnLineSidePrecise(viewpoint.Path[0], dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], dst)) { double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length(); @@ -312,8 +297,8 @@ void PolyDrawLinePortal::SaveGlobals() } } - //camera = nullptr; - //viewsector = R_PointInSubsector(ViewPos)->sector; + viewpoint.camera = nullptr; + viewpoint.sector = R_PointInSubsector(viewpoint.Pos)->sector; R_SetViewAngle(viewpoint, viewwindow); if (Mirror) diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp index 21ae23fc8..ad0d88d34 100644 --- a/src/polyrenderer/scene/poly_scene.cpp +++ b/src/polyrenderer/scene/poly_scene.cpp @@ -219,7 +219,7 @@ void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDe } // Render wall, and update culling info if its an occlusion blocker - if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals)) + if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine)) { Cull.MarkSegmentCulled(angle1, angle2); } @@ -319,7 +319,7 @@ void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *fronts } // Render wall, and update culling info if its an occlusion blocker - if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals)) + if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine)) { Cull.MarkSegmentCulled(angle1, angle2); } diff --git a/src/polyrenderer/scene/poly_scene.h b/src/polyrenderer/scene/poly_scene.h index fc89de7cd..8dafc949b 100644 --- a/src/polyrenderer/scene/poly_scene.h +++ b/src/polyrenderer/scene/poly_scene.h @@ -80,6 +80,8 @@ public: static const uint32_t SkySubsectorDepth = 0x7fffffff; + line_t *LastPortalLine = nullptr; + private: void ClearBuffers(); void RenderPortals(int portalDepth); diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index 3b637b472..87ee9ec12 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -37,36 +37,51 @@ EXTERN_CVAR(Bool, r_drawmirrors) -bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals) +bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals, line_t *lastPortalLine) { + double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1); + double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1); + double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2); + double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2); + double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling); + double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor); + PolyDrawLinePortal *polyportal = nullptr; if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors)) { - if (PolyRenderer::Instance()->InsertSeenMirror(line->linedef)) + if (lastPortalLine == line->linedef || + (line->linedef->v1->fX() * clipPlane.A + line->linedef->v1->fY() * clipPlane.B + clipPlane.D <= 0.0f) || + (line->linedef->v2->fX() * clipPlane.A + line->linedef->v2->fY() * clipPlane.B + clipPlane.D <= 0.0f)) { - linePortals.push_back(std::unique_ptr(new PolyDrawLinePortal(line->linedef))); - polyportal = linePortals.back().get(); + return false; } + + linePortals.push_back(std::unique_ptr(new PolyDrawLinePortal(line->linedef))); + polyportal = linePortals.back().get(); } else if (line->linedef && line->linedef->isVisualPortal()) { - FLinePortal *portal = line->linedef->getPortal(); - if (PolyRenderer::Instance()->InsertSeenLinePortal(portal)) + if (lastPortalLine == line->linedef || + (line->linedef->v1->fX() * clipPlane.A + line->linedef->v1->fY() * clipPlane.B + clipPlane.D <= 0.0f) || + (line->linedef->v2->fX() * clipPlane.A + line->linedef->v2->fY() * clipPlane.B + clipPlane.D <= 0.0f)) { - for (auto &p : linePortals) + return false; + } + + FLinePortal *portal = line->linedef->getPortal(); + for (auto &p : linePortals) + { + if (p->Portal == portal) // To do: what other criterias do we need to check for? { - if (p->Portal == portal) // To do: what other criterias do we need to check for? - { - polyportal = p.get(); - break; - } - } - if (!polyportal) - { - linePortals.push_back(std::unique_ptr(new PolyDrawLinePortal(portal))); - polyportal = linePortals.back().get(); + polyportal = p.get(); + break; } } + if (!polyportal) + { + linePortals.push_back(std::unique_ptr(new PolyDrawLinePortal(portal))); + polyportal = linePortals.back().get(); + } } RenderPolyWall wall; @@ -78,13 +93,6 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan wall.SubsectorDepth = subsectorDepth; wall.StencilValue = stencilValue; - double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1); - double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1); - double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2); - double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2); - double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling); - double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor); - if (line->backsector == nullptr) { if (line->sidedef) @@ -244,6 +252,14 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c vertices[3].u = (float)texcoordsU.u1; vertices[3].v = (float)texcoordsVLeft.v2; } + else + { + for (int i = 0; i < 4; i++) + { + vertices[i].u = 0.0f; + vertices[i].v = 0.0f; + } + } // Masked walls clamp to the 0-1 range (no texture repeat) if (Masked) @@ -259,7 +275,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c args.SetFaceCullCCW(true); args.SetStencilTestValue(StencilValue); args.SetWriteStencil(true, StencilValue + 1); - if (tex) + if (tex && !Polyportal) args.SetTexture(tex); args.SetClipPlane(clipPlane); @@ -270,10 +286,6 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c args.SetWriteSubsectorDepth(false); args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan); Polyportal->Shape.push_back({ vertices, 4, true, SubsectorDepth }); - - angle_t angle1, angle2; - if (cull.GetAnglesForLine(v1.X, v1.Y, v2.X, v2.Y, angle1, angle2)) - Polyportal->Segments.push_back({ angle1, angle2 }); } else if (!Masked) { diff --git a/src/polyrenderer/scene/poly_wall.h b/src/polyrenderer/scene/poly_wall.h index 8a38447c8..f519b4a55 100644 --- a/src/polyrenderer/scene/poly_wall.h +++ b/src/polyrenderer/scene/poly_wall.h @@ -31,7 +31,7 @@ class PolyCull; class RenderPolyWall { public: - static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals); + static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals, line_t *lastPortalLine); static void Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput); void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);