From f1df400cc7c7256530d00b94de37a23767f82b6b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 9 Dec 2016 03:17:35 +0100 Subject: [PATCH] Add some portal segment culling and disable sector portals for now --- src/r_poly_cull.cpp | 15 ++++++++-- src/r_poly_cull.h | 5 ++-- src/r_poly_plane.cpp | 66 +++++++++++++++++++++++++++++++++++++++---- src/r_poly_plane.h | 5 ++-- src/r_poly_portal.cpp | 4 ++- src/r_poly_portal.h | 10 +++++++ src/r_poly_scene.cpp | 22 ++++++++++++--- src/r_poly_scene.h | 3 ++ src/r_poly_wall.cpp | 21 ++++++++------ src/r_poly_wall.h | 7 +++-- 10 files changed, 129 insertions(+), 29 deletions(-) diff --git a/src/r_poly_cull.cpp b/src/r_poly_cull.cpp index a688c26444..59b7c0c5a3 100644 --- a/src/r_poly_cull.cpp +++ b/src/r_poly_cull.cpp @@ -30,7 +30,6 @@ void PolyCull::CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane) { - ClearSolidSegments(); PvsSectors.clear(); frustumPlanes = FrustumPlanes(worldToClip); PortalClipPlane = portalClipPlane; @@ -42,8 +41,6 @@ void PolyCull::CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPl CullSubsector(subsectors); else CullNode(nodes + numnodes - 1); // The head node is the last node output. - - ClearSolidSegments(); } void PolyCull::CullNode(void *node) @@ -109,6 +106,18 @@ void PolyCull::ClearSolidSegments() SolidSegments.push_back({ SolidCullScale , 0x7fff }); } +void PolyCull::InvertSegments() +{ + TempInvertSolidSegments.swap(SolidSegments); + ClearSolidSegments(); + int x = -0x7fff; + for (const auto &segment : TempInvertSolidSegments) + { + MarkSegmentCulled(x, segment.X1 - 1); + x = segment.X2 + 1; + } +} + bool PolyCull::IsSegmentCulled(int x1, int x2) const { x1 = clamp(x1, -0x7ffe, 0x7ffd); diff --git a/src/r_poly_cull.h b/src/r_poly_cull.h index fe3cd9f5d3..4c0cfe314b 100644 --- a/src/r_poly_cull.h +++ b/src/r_poly_cull.h @@ -35,11 +35,13 @@ enum class LineSegmentRange class PolyCull { public: + void ClearSolidSegments(); void CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane); 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; + void InvertSegments(); std::vector PvsSectors; double MaxCeilingHeight = 0.0; @@ -60,9 +62,8 @@ private: // Returns true if some part of the bbox might be visible. bool CheckBBox(float *bspcoord); - void ClearSolidSegments(); - std::vector SolidSegments; + std::vector TempInvertSolidSegments; const int SolidCullScale = 3000; FrustumPlanes frustumPlanes; diff --git a/src/r_poly_plane.cpp b/src/r_poly_plane.cpp index 24b00af000..c7f011a760 100644 --- a/src/r_poly_plane.cpp +++ b/src/r_poly_plane.cpp @@ -32,7 +32,7 @@ EXTERN_CVAR(Int, r_3dfloors) -void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals) +void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals) { RenderPolyPlane plane; @@ -84,8 +84,8 @@ void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const Vec4f &cl } } - plane.Render(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, true, skyCeilingHeight, sectorPortals); - plane.Render(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals); + plane.Render(worldToClip, clipPlane, cull, sub, subsectorDepth, stencilValue, true, skyCeilingHeight, sectorPortals); + plane.Render(worldToClip, clipPlane, cull, sub, subsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals); } void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor) @@ -147,9 +147,10 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); } -void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) +void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) { - FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); + std::vector portalSegments; + FSectorPortal *portal = nullptr;// sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); PolyDrawSectorPortal *polyportal = nullptr; if (portal && (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into portal = nullptr; @@ -157,7 +158,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan { for (auto &p : sectorPortals) { - if (p->Portal == portal) // To do: what other criterias do we need to check for? + if (p->Portal == portal) // To do: what other criteria do we need to check for? { polyportal = p.get(); break; @@ -168,6 +169,54 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan sectorPortals.push_back(std::make_unique(portal, ceiling)); polyportal = sectorPortals.back().get(); } + + // Calculate portal clipping + + DVector2 v; + bool inside = true; + double vdist = 1.0e10; + + portalSegments.reserve(sub->numlines); + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + + DVector2 pt1 = line->v1->fPos() - ViewPos; + DVector2 pt2 = line->v2->fPos() - ViewPos; + if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0) + inside = false; + + double dist = pt1.LengthSquared(); + if (dist < vdist) + { + v = line->v1->fPos(); + vdist = dist; + } + dist = pt2.LengthSquared(); + if (dist < vdist) + { + v = line->v2->fPos(); + vdist = dist; + } + + int sx1, sx2; + LineSegmentRange range = cull.GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2); + if (range == LineSegmentRange::HasSegment) + portalSegments.push_back({ sx1, sx2 }); + } + + if (inside) + { + polyportal->PortalPlane = Vec4f(0.0f, 0.0f, 0.0f, 1.0f); + } + else if(polyportal->PortalPlane == Vec4f(0.0f) || Vec4f::dot(polyportal->PortalPlane, Vec4f((float)v.X, (float)v.Y, 0.0f, 1.0f)) > 0.0f) + { + DVector2 planePos = v; + DVector2 planeNormal = v - ViewPos; + planeNormal.MakeUnit(); + double planeD = -(planeNormal | (planePos + planeNormal * 0.001)); + polyportal->PortalPlane = Vec4f((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD); + } } sector_t *fakesector = sub->sector->heightsec; @@ -300,6 +349,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan args.stencilwritevalue = polyportal->StencilValue; PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth }); + polyportal->Segments.insert(polyportal->Segments.end(), portalSegments.begin(), portalSegments.end()); } } else @@ -308,6 +358,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan { args.stencilwritevalue = polyportal->StencilValue; polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth }); + polyportal->Segments.insert(polyportal->Segments.end(), portalSegments.begin(), portalSegments.end()); } else { @@ -385,7 +436,10 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); if (portal) + { polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth }); + polyportal->Segments.insert(polyportal->Segments.end(), portalSegments.begin(), portalSegments.end()); + } } } } diff --git a/src/r_poly_plane.h b/src/r_poly_plane.h index 396a9e4a88..be307b4e23 100644 --- a/src/r_poly_plane.h +++ b/src/r_poly_plane.h @@ -25,12 +25,13 @@ #include "r_poly_triangle.h" class PolyDrawSectorPortal; +class PolyCull; class Vec4f; class RenderPolyPlane { public: - static void RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals); + static void RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals); private: struct UVTransform @@ -48,6 +49,6 @@ private: }; void Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor); - void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); TriVertex PlaneVertex(vertex_t *v1, double height, const UVTransform &transform); }; diff --git a/src/r_poly_portal.cpp b/src/r_poly_portal.cpp index 96df9daf09..580622c1fb 100644 --- a/src/r_poly_portal.cpp +++ b/src/r_poly_portal.cpp @@ -64,7 +64,8 @@ void PolyDrawSectorPortal::Render(int portalDepth) TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z); TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; - RenderPortal.SetViewpoint(worldToClip, Vec4f(0.0f, 0.0f, 0.0f, 1.0f), StencilValue); + RenderPortal.SetViewpoint(worldToClip, PortalPlane, StencilValue); + RenderPortal.SetPortalSegments(Segments); RenderPortal.Render(portalDepth); RestoreGlobals(); @@ -175,6 +176,7 @@ void PolyDrawLinePortal::Render(int portalDepth) Vec4f portalPlane((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD); RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue); + RenderPortal.SetPortalSegments(Segments); RenderPortal.Render(portalDepth); RestoreGlobals(); diff --git a/src/r_poly_portal.h b/src/r_poly_portal.h index 6cad98ff6a..4f23567610 100644 --- a/src/r_poly_portal.h +++ b/src/r_poly_portal.h @@ -33,6 +33,13 @@ struct PolyPortalVertexRange uint32_t SubsectorDepth; }; +class PolyPortalSegment +{ +public: + PolyPortalSegment(int x1, int x2) : X1(x1), X2(x2) { } + int X1, X2; +}; + class PolyDrawSectorPortal { public: @@ -44,6 +51,8 @@ public: FSectorPortal *Portal = nullptr; uint32_t StencilValue = 0; std::vector Shape; + std::vector Segments; + Vec4f PortalPlane = Vec4f(0.0f); private: void SaveGlobals(); @@ -73,6 +82,7 @@ public: line_t *Mirror = nullptr; uint32_t StencilValue = 0; std::vector Shape; + std::vector Segments; private: void SaveGlobals(); diff --git a/src/r_poly_scene.cpp b/src/r_poly_scene.cpp index 3b03507f17..c0697f55ed 100644 --- a/src/r_poly_scene.cpp +++ b/src/r_poly_scene.cpp @@ -50,10 +50,24 @@ void RenderPolyScene::SetViewpoint(const TriMatrix &worldToClip, const Vec4f &po PortalPlane = portalPlane; } +void RenderPolyScene::SetPortalSegments(const std::vector &segments) +{ + Cull.ClearSolidSegments(); + for (const auto &segment : segments) + { + Cull.MarkSegmentCulled(segment.X1, segment.X2); + } + Cull.InvertSegments(); + PortalSegmentsAdded = true; +} + void RenderPolyScene::Render(int portalDepth) { ClearBuffers(); + if (!PortalSegmentsAdded) + Cull.ClearSolidSegments(); Cull.CullScene(WorldToClip, PortalPlane); + Cull.ClearSolidSegments(); RenderSectors(); RenderPortals(portalDepth); } @@ -91,7 +105,7 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub) if (sub->sector->CenterFloor() != sub->sector->CenterCeiling()) { - RenderPolyPlane::RenderPlanes(WorldToClip, PortalPlane, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); + RenderPolyPlane::RenderPlanes(WorldToClip, PortalPlane, Cull, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); } for (uint32_t i = 0; i < sub->numlines; i++) @@ -199,12 +213,12 @@ void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *fronts if (!(fakeFloor->flags & FF_EXISTS)) continue; if (!(fakeFloor->flags & FF_RENDERPLANES)) continue; if (!fakeFloor->model) continue; - RenderPolyWall::Render3DFloorLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, fakeFloor, TranslucentObjects); + RenderPolyWall::Render3DFloorLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, fakeFloor, TranslucentObjects); } } // Render wall, and update culling info if its an occlusion blocker - if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals)) + if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals)) { if (segmentRange == LineSegmentRange::HasSegment) Cull.MarkSegmentCulled(sx1, sx2); @@ -332,7 +346,7 @@ void RenderPolyScene::RenderTranslucent(int portalDepth) } else if (!obj.thing) { - obj.wall.Render(WorldToClip, PortalPlane); + obj.wall.Render(WorldToClip, PortalPlane, Cull); } else if ((obj.thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) { diff --git a/src/r_poly_scene.h b/src/r_poly_scene.h index 1e3037b124..00502e53ee 100644 --- a/src/r_poly_scene.h +++ b/src/r_poly_scene.h @@ -67,6 +67,7 @@ public: class PolyDrawSectorPortal; class PolyDrawLinePortal; +class PolyPortalSegment; // Renders everything from a specific viewpoint class RenderPolyScene @@ -75,6 +76,7 @@ public: RenderPolyScene(); ~RenderPolyScene(); void SetViewpoint(const TriMatrix &worldToClip, const Vec4f &portalPlane, uint32_t stencilValue); + void SetPortalSegments(const std::vector &segments); void Render(int portalDepth); void RenderTranslucent(int portalDepth); @@ -100,4 +102,5 @@ private: std::vector> SectorPortals; std::vector> LinePortals; + bool PortalSegmentsAdded = false; }; diff --git a/src/r_poly_wall.cpp b/src/r_poly_wall.cpp index efc9530138..bcb5bb16b2 100644 --- a/src/r_poly_wall.cpp +++ b/src/r_poly_wall.cpp @@ -35,7 +35,7 @@ EXTERN_CVAR(Bool, r_drawmirrors) -bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, 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 Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals) { PolyDrawLinePortal *polyportal = nullptr; if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors)) @@ -91,7 +91,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP wall.UnpeggedCeil = frontceilz1; wall.Texpart = side_t::mid; wall.Polyportal = polyportal; - wall.Render(worldToClip, clipPlane); + wall.Render(worldToClip, clipPlane, cull); return true; } } @@ -126,7 +126,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP wall.BottomZ = topfloorz1; wall.UnpeggedCeil = topceilz1; wall.Texpart = side_t::top; - wall.Render(worldToClip, clipPlane); + wall.Render(worldToClip, clipPlane, cull); } if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef) @@ -136,7 +136,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP wall.BottomZ = bottomfloorz2; wall.UnpeggedCeil = topceilz1; wall.Texpart = side_t::bottom; - wall.Render(worldToClip, clipPlane); + wall.Render(worldToClip, clipPlane, cull); } if (line->sidedef) @@ -155,14 +155,14 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP if (polyportal) { wall.Polyportal = polyportal; - wall.Render(worldToClip, clipPlane); + wall.Render(worldToClip, clipPlane, cull); } } } return polyportal != nullptr; } -void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput) +void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput) { double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1); double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1); @@ -182,7 +182,7 @@ void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f wall.BottomZ = frontfloorz1; wall.UnpeggedCeil = frontceilz1; wall.Texpart = side_t::mid; - wall.Render(worldToClip, clipPlane); + wall.Render(worldToClip, clipPlane, cull); } void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2) @@ -195,7 +195,7 @@ void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ce this->floor2 = floor2; } -void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane) +void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull) { FTexture *tex = GetTexture(); if (!tex && !Polyportal) @@ -266,6 +266,11 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane args.stencilwritevalue = Polyportal->StencilValue; PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); Polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, args.uniforms.subsectorDepth }); + + int sx1, sx2; + LineSegmentRange range = cull.GetSegmentRangeForLine(v1.X, v1.Y, v2.X, v2.Y, sx1, sx2); + if (range == LineSegmentRange::HasSegment) + Polyportal->Segments.push_back({ sx1, sx2 }); } else if (!Masked) { diff --git a/src/r_poly_wall.h b/src/r_poly_wall.h index bcecd5a05b..8443a174ad 100644 --- a/src/r_poly_wall.h +++ b/src/r_poly_wall.h @@ -26,16 +26,17 @@ class PolyTranslucentObject; class PolyDrawLinePortal; +class PolyCull; class Vec4f; class RenderPolyWall { public: - static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals); - static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput); + static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals); + static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &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); - void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull); DVector2 v1; DVector2 v2;