- improve sector portals rendering in softpoly

- fix a softpoly memory leak and change vertex list to be allocated using the frame allocator
This commit is contained in:
Magnus Norddahl 2017-03-24 07:28:28 +01:00
parent b5720ee1e7
commit f178646e1a
13 changed files with 98 additions and 131 deletions

View file

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

View file

@ -61,10 +61,3 @@ private:
std::vector<uint8_t> values;
std::vector<uint32_t> masks;
};
class PolyVertexBuffer
{
public:
static TriVertex *GetVertices(int count);
static void Clear();
};

View file

@ -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;

View file

@ -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);

View file

@ -58,6 +58,7 @@ private:
std::vector<SolidSegment> SolidSegments;
std::vector<SolidSegment> TempInvertSolidSegments;
const int SolidCullScale = 3000;
bool FirstSkyHeight = true;
FrustumPlanes frustumPlanes;
Vec4f PortalClipPlane;

View file

@ -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<TriVertex>(4);
bool foggy = false;
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;

View file

@ -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<TriVertex>(4);
bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;

View file

@ -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<TriVertex>(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<PolyPortalSegment> 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<TriVertex>(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<TriVertex>(4);
seg_t *line = &sub->firstline[i];

View file

@ -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);

View file

@ -52,7 +52,6 @@ public:
uint32_t StencilValue = 0;
std::vector<PolyPortalVertexRange> Shape;
std::vector<PolyPortalSegment> Segments;
Vec4f PortalPlane = Vec4f(0.0f);
private:
void SaveGlobals();

View file

@ -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<TriVertex>(4);
bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;

View file

@ -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<TriVertex>(4);
vertices[0].x = (float)v1.X;
vertices[0].y = (float)v1.Y;

View file

@ -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<TriVertex>(4);
bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;