From f178646e1a1e79dbe2e838b4a5776eda8392b5ed Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 24 Mar 2017 07:28:28 +0100 Subject: [PATCH] - improve sector portals rendering in softpoly - fix a softpoly memory leak and change vertex list to be allocated using the frame allocator --- src/polyrenderer/drawers/poly_buffer.cpp | 24 ----- src/polyrenderer/drawers/poly_buffer.h | 7 -- src/polyrenderer/poly_renderer.cpp | 2 +- src/polyrenderer/scene/poly_cull.cpp | 16 ++- src/polyrenderer/scene/poly_cull.h | 1 + src/polyrenderer/scene/poly_decal.cpp | 4 +- src/polyrenderer/scene/poly_particle.cpp | 4 +- src/polyrenderer/scene/poly_plane.cpp | 110 ++++++--------------- src/polyrenderer/scene/poly_portal.cpp | 45 ++++++++- src/polyrenderer/scene/poly_portal.h | 1 - src/polyrenderer/scene/poly_sprite.cpp | 4 +- src/polyrenderer/scene/poly_wall.cpp | 7 +- src/polyrenderer/scene/poly_wallsprite.cpp | 4 +- 13 files changed, 98 insertions(+), 131 deletions(-) diff --git a/src/polyrenderer/drawers/poly_buffer.cpp b/src/polyrenderer/drawers/poly_buffer.cpp index 291e05acb..e8d37af4c 100644 --- a/src/polyrenderer/drawers/poly_buffer.cpp +++ b/src/polyrenderer/drawers/poly_buffer.cpp @@ -74,27 +74,3 @@ void PolyStencilBuffer::Clear(int newwidth, int newheight, uint8_t stencil_value m[i] = 0xffffff00 | stencil_value; } } - -///////////////////////////////////////////////////////////////////////////// - -namespace -{ - int NextBufferVertex = 0; -} - -TriVertex *PolyVertexBuffer::GetVertices(int count) -{ - enum { VertexBufferSize = 256 * 1024 }; - static TriVertex Vertex[VertexBufferSize]; - - if (NextBufferVertex + count > VertexBufferSize) - return nullptr; - TriVertex *v = Vertex + NextBufferVertex; - NextBufferVertex += count; - return v; -} - -void PolyVertexBuffer::Clear() -{ - NextBufferVertex = 0; -} diff --git a/src/polyrenderer/drawers/poly_buffer.h b/src/polyrenderer/drawers/poly_buffer.h index a135722fd..c272a7710 100644 --- a/src/polyrenderer/drawers/poly_buffer.h +++ b/src/polyrenderer/drawers/poly_buffer.h @@ -61,10 +61,3 @@ private: std::vector values; std::vector masks; }; - -class PolyVertexBuffer -{ -public: - static TriVertex *GetVertices(int count); - static void Clear(); -}; diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index 662e0324b..2e400975f 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -154,7 +154,7 @@ void PolyRenderer::RenderRemainingPlayerSprites() void PolyRenderer::ClearBuffers() { - PolyVertexBuffer::Clear(); + FrameMemory.Clear(); PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0); PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight()); NextStencilValue = 0; diff --git a/src/polyrenderer/scene/poly_cull.cpp b/src/polyrenderer/scene/poly_cull.cpp index c8fd1f5d1..6fe591527 100644 --- a/src/polyrenderer/scene/poly_cull.cpp +++ b/src/polyrenderer/scene/poly_cull.cpp @@ -35,6 +35,7 @@ void PolyCull::CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPl PortalClipPlane = portalClipPlane; // Cull front to back + FirstSkyHeight = true; MaxCeilingHeight = 0.0; MinFloorHeight = 0.0; if (level.nodes.Size() == 0) @@ -71,8 +72,17 @@ void PolyCull::CullNode(void *node) void PolyCull::CullSubsector(subsector_t *sub) { // Update sky heights for the scene - MaxCeilingHeight = MAX(MaxCeilingHeight, sub->sector->ceilingplane.Zat0()); - MinFloorHeight = MIN(MinFloorHeight, sub->sector->floorplane.Zat0()); + if (!FirstSkyHeight) + { + MaxCeilingHeight = MAX(MaxCeilingHeight, sub->sector->ceilingplane.Zat0()); + MinFloorHeight = MIN(MinFloorHeight, sub->sector->floorplane.Zat0()); + } + else + { + MaxCeilingHeight = sub->sector->ceilingplane.Zat0(); + MinFloorHeight = sub->sector->floorplane.Zat0(); + FirstSkyHeight = false; + } // Mark that we need to render this PvsSectors.push_back(sub); @@ -246,6 +256,7 @@ 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)); @@ -269,6 +280,7 @@ bool PolyCull::GetAnglesForLine(double x1, double y1, double x2, double y2, angl y1 = ny1; y2 = ny2; } +#endif angle2 = PointToPseudoAngle(x1, y1); angle1 = PointToPseudoAngle(x2, y2); diff --git a/src/polyrenderer/scene/poly_cull.h b/src/polyrenderer/scene/poly_cull.h index 9fc6f9e99..d217de7ef 100644 --- a/src/polyrenderer/scene/poly_cull.h +++ b/src/polyrenderer/scene/poly_cull.h @@ -58,6 +58,7 @@ private: std::vector SolidSegments; std::vector TempInvertSolidSegments; const int SolidCullScale = 3000; + bool FirstSkyHeight = true; FrustumPlanes frustumPlanes; Vec4f PortalClipPlane; diff --git a/src/polyrenderer/scene/poly_decal.cpp b/src/polyrenderer/scene/poly_decal.cpp index c77d6a040..0759ac64d 100644 --- a/src/polyrenderer/scene/poly_decal.cpp +++ b/src/polyrenderer/scene/poly_decal.cpp @@ -102,9 +102,7 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan DVector2 points[2] = { decal_left, decal_right }; - TriVertex *vertices = PolyVertexBuffer::GetVertices(4); - if (!vertices) - return; + TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory(4); bool foggy = false; int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4; diff --git a/src/polyrenderer/scene/poly_particle.cpp b/src/polyrenderer/scene/poly_particle.cpp index 94618ef38..8d09be467 100644 --- a/src/polyrenderer/scene/poly_particle.cpp +++ b/src/polyrenderer/scene/poly_particle.cpp @@ -43,9 +43,7 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipP { pos.X + viewpoint.Sin * psize, pos.Y - viewpoint.Cos * psize } }; - TriVertex *vertices = PolyVertexBuffer::GetVertices(4); - if (!vertices) - return; + TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory(4); bool foggy = false; int actualextralight = foggy ? 0 : viewpoint.extralight << 4; diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp index ee762742e..03ea75b37 100644 --- a/src/polyrenderer/scene/poly_plane.cpp +++ b/src/polyrenderer/scene/poly_plane.cpp @@ -119,9 +119,7 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c args.uniforms.flags = TriUniforms::nearest_filter; args.uniforms.subsectorDepth = subsectorDepth; - TriVertex *vertices = PolyVertexBuffer::GetVertices(sub->numlines); - if (!vertices) - return; + TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory(sub->numlines); if (ceiling) { @@ -234,16 +232,23 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan if (tex->UseType == FTexture::TEX_Null) return; - bool isSky = picnum == skyflatnum; - std::vector portalSegments; FSectorPortal *portal = 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; - + + bool isSky = portal || picnum == skyflatnum; + if (portal) { + // Skip portals not facing the camera + if ((ceiling && frontsector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) || + (!ceiling && frontsector->floorplane.PointOnSide(viewpoint.Pos) < 0)) + { + return; + } + for (auto &p : sectorPortals) { if (p->Portal == portal) // To do: what other criteria do we need to check for? @@ -258,65 +263,30 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan polyportal = sectorPortals.back().get(); } +#if 0 // Calculate portal clipping - - if (!isSky) + portalSegments.reserve(sub->numlines); + for (uint32_t i = 0; i < sub->numlines; i++) { - DVector2 v; - bool inside = true; - double vdist = 1.0e10; + seg_t *line = &sub->firstline[i]; - portalSegments.reserve(sub->numlines); - for (uint32_t i = 0; i < sub->numlines; i++) + DVector2 pt1 = line->v1->fPos() - viewpoint.Pos; + DVector2 pt2 = line->v2->fPos() - viewpoint.Pos; + bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0; + if (!backside) { - seg_t *line = &sub->firstline[i]; - - DVector2 pt1 = line->v1->fPos() - viewpoint.Pos; - DVector2 pt2 = line->v2->fPos() - viewpoint.Pos; - bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0; - if (backside) - 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; - } - - if (!backside) - { - angle_t angle1, angle2; - if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2)) - portalSegments.push_back({ angle1, angle2 }); - } - else - { - angle_t angle1, angle2; - if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2)) - portalSegments.push_back({ angle1, angle2 }); - } + angle_t angle1, angle2; + if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2)) + portalSegments.push_back({ angle1, angle2 }); } - - if (inside) + else { - 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 - viewpoint.Pos; - planeNormal.MakeUnit(); - double planeD = -(planeNormal | (planePos + planeNormal * 0.001)); - polyportal->PortalPlane = Vec4f((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD); + angle_t angle1, angle2; + if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2)) + portalSegments.push_back({ angle1, angle2 }); } } +#endif } UVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex); @@ -331,9 +301,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan args.uniforms.flags = TriUniforms::nearest_filter; args.uniforms.subsectorDepth = isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth; - TriVertex *vertices = PolyVertexBuffer::GetVertices(sub->numlines); - if (!vertices) - return; + TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory(sub->numlines); if (ceiling) { @@ -364,21 +332,9 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan if (!isSky) { - if (!portal) - { - args.SetTexture(tex); - args.blendmode = TriBlendMode::Copy; - PolyTriangleDrawer::draw(args); - } - else - { - args.stencilwritevalue = polyportal->StencilValue; - args.writeColor = false; - args.writeSubsector = false; - PolyTriangleDrawer::draw(args); - polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth }); - polyportal->Segments.insert(polyportal->Segments.end(), portalSegments.begin(), portalSegments.end()); - } + args.SetTexture(tex); + args.blendmode = TriBlendMode::Copy; + PolyTriangleDrawer::draw(args); } else { @@ -398,9 +354,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan for (uint32_t i = 0; i < sub->numlines; i++) { - TriVertex *wallvert = PolyVertexBuffer::GetVertices(4); - if (!wallvert) - return; + TriVertex *wallvert = PolyRenderer::Instance()->FrameMemory.AllocMemory(4); seg_t *line = &sub->firstline[i]; diff --git a/src/polyrenderer/scene/poly_portal.cpp b/src/polyrenderer/scene/poly_portal.cpp index c35a97250..f26213455 100644 --- a/src/polyrenderer/scene/poly_portal.cpp +++ b/src/polyrenderer/scene/poly_portal.cpp @@ -43,10 +43,51 @@ void PolyDrawSectorPortal::Render(int portalDepth) if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE) return; + const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; + + Vec4f portalPlane = Vec4f(0.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.x = 0.0f; + portalPlane.y = 0.0f; + portalPlane.z = 1.0f; + portalPlane.w = -minHeight; + } + else if (!first && maxHeight < viewpoint.Pos.Z) + { + portalPlane.x = 0.0f; + portalPlane.y = 0.0f; + portalPlane.z = -1.0f; + portalPlane.w = maxHeight; + } + } + SaveGlobals(); // To do: get this information from PolyRenderer instead of duplicating the code.. - const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; const auto &viewwindow = PolyRenderer::Instance()->Viewwindow; double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians(); double angx = cos(radPitch); @@ -65,7 +106,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; - RenderPortal.SetViewpoint(worldToClip, PortalPlane, StencilValue); + RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue); RenderPortal.SetPortalSegments(Segments); RenderPortal.Render(portalDepth); diff --git a/src/polyrenderer/scene/poly_portal.h b/src/polyrenderer/scene/poly_portal.h index d1a0e53f3..266313e40 100644 --- a/src/polyrenderer/scene/poly_portal.h +++ b/src/polyrenderer/scene/poly_portal.h @@ -52,7 +52,6 @@ public: uint32_t StencilValue = 0; std::vector Shape; std::vector Segments; - Vec4f PortalPlane = Vec4f(0.0f); private: void SaveGlobals(); diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp index fa197eb89..6e3c8c86c 100644 --- a/src/polyrenderer/scene/poly_sprite.cpp +++ b/src/polyrenderer/scene/poly_sprite.cpp @@ -102,9 +102,7 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla // Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here.. //R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS); - TriVertex *vertices = PolyVertexBuffer::GetVertices(4); - if (!vertices) - return; + TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory(4); bool foggy = false; int actualextralight = foggy ? 0 : viewpoint.extralight << 4; diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index 3d48f1423..078b10e0d 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -120,6 +120,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP double middlefloorz2 = MIN(bottomceilz2, middleceilz2); bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum; + bool bothSkyFloor = frontsector->GetTexture(sector_t::floor) == skyflatnum && backsector->GetTexture(sector_t::floor) == skyflatnum; if ((topceilz1 > topfloorz1 || topceilz2 > topfloorz2) && line->sidedef && !bothSkyCeiling) { @@ -131,7 +132,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP wall.Render(worldToClip, clipPlane, cull); } - if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef) + if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef && !bothSkyFloor) { wall.SetCoords(line->v1->fPos(), line->v2->fPos(), bottomceilz1, bottomfloorz1, bottomceilz2, bottomfloorz2); wall.TopZ = bottomceilz1; @@ -204,9 +205,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane if (!tex && !Polyportal) return; - TriVertex *vertices = PolyVertexBuffer::GetVertices(4); - if (!vertices) - return; + TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory(4); vertices[0].x = (float)v1.X; vertices[0].y = (float)v1.Y; diff --git a/src/polyrenderer/scene/poly_wallsprite.cpp b/src/polyrenderer/scene/poly_wallsprite.cpp index bbefbe91e..75227c255 100644 --- a/src/polyrenderer/scene/poly_wallsprite.cpp +++ b/src/polyrenderer/scene/poly_wallsprite.cpp @@ -69,9 +69,7 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &cli DVector2 points[2] = { left, right }; - TriVertex *vertices = PolyVertexBuffer::GetVertices(4); - if (!vertices) - return; + TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory(4); bool foggy = false; int actualextralight = foggy ? 0 : viewpoint.extralight << 4;