- 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; 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<uint8_t> values;
std::vector<uint32_t> masks; 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() void PolyRenderer::ClearBuffers()
{ {
PolyVertexBuffer::Clear(); FrameMemory.Clear();
PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0); PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0);
PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight()); PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight());
NextStencilValue = 0; NextStencilValue = 0;

View file

@ -35,6 +35,7 @@ void PolyCull::CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPl
PortalClipPlane = portalClipPlane; PortalClipPlane = portalClipPlane;
// Cull front to back // Cull front to back
FirstSkyHeight = true;
MaxCeilingHeight = 0.0; MaxCeilingHeight = 0.0;
MinFloorHeight = 0.0; MinFloorHeight = 0.0;
if (level.nodes.Size() == 0) if (level.nodes.Size() == 0)
@ -71,8 +72,17 @@ void PolyCull::CullNode(void *node)
void PolyCull::CullSubsector(subsector_t *sub) void PolyCull::CullSubsector(subsector_t *sub)
{ {
// Update sky heights for the scene // Update sky heights for the scene
MaxCeilingHeight = MAX(MaxCeilingHeight, sub->sector->ceilingplane.Zat0()); if (!FirstSkyHeight)
MinFloorHeight = MIN(MinFloorHeight, sub->sector->floorplane.Zat0()); {
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 // Mark that we need to render this
PvsSectors.push_back(sub); 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 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 // Clip line to the portal clip plane
float distance1 = Vec4f::dot(PortalClipPlane, Vec4f((float)x1, (float)y1, 0.0f, 1.0f)); 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)); 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; y1 = ny1;
y2 = ny2; y2 = ny2;
} }
#endif
angle2 = PointToPseudoAngle(x1, y1); angle2 = PointToPseudoAngle(x1, y1);
angle1 = PointToPseudoAngle(x2, y2); angle1 = PointToPseudoAngle(x2, y2);

View file

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

View file

@ -102,9 +102,7 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
DVector2 points[2] = { decal_left, decal_right }; DVector2 points[2] = { decal_left, decal_right };
TriVertex *vertices = PolyVertexBuffer::GetVertices(4); TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
if (!vertices)
return;
bool foggy = false; bool foggy = false;
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4; 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 } { pos.X + viewpoint.Sin * psize, pos.Y - viewpoint.Cos * psize }
}; };
TriVertex *vertices = PolyVertexBuffer::GetVertices(4); TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
if (!vertices)
return;
bool foggy = false; bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4; 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.flags = TriUniforms::nearest_filter;
args.uniforms.subsectorDepth = subsectorDepth; args.uniforms.subsectorDepth = subsectorDepth;
TriVertex *vertices = PolyVertexBuffer::GetVertices(sub->numlines); TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(sub->numlines);
if (!vertices)
return;
if (ceiling) if (ceiling)
{ {
@ -234,16 +232,23 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
if (tex->UseType == FTexture::TEX_Null) if (tex->UseType == FTexture::TEX_Null)
return; return;
bool isSky = picnum == skyflatnum;
std::vector<PolyPortalSegment> portalSegments; std::vector<PolyPortalSegment> portalSegments;
FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor);
PolyDrawSectorPortal *polyportal = nullptr; PolyDrawSectorPortal *polyportal = nullptr;
if (portal && (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into if (portal && (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into
portal = nullptr; portal = nullptr;
bool isSky = portal || picnum == skyflatnum;
if (portal) 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) for (auto &p : sectorPortals)
{ {
if (p->Portal == portal) // To do: what other criteria do we need to check for? 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(); polyportal = sectorPortals.back().get();
} }
#if 0
// Calculate portal clipping // Calculate portal clipping
portalSegments.reserve(sub->numlines);
if (!isSky) for (uint32_t i = 0; i < sub->numlines; i++)
{ {
DVector2 v; seg_t *line = &sub->firstline[i];
bool inside = true;
double vdist = 1.0e10;
portalSegments.reserve(sub->numlines); DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
for (uint32_t i = 0; i < sub->numlines; i++) 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]; angle_t angle1, angle2;
if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos; portalSegments.push_back({ angle1, angle2 });
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 });
}
} }
else
if (inside)
{ {
polyportal->PortalPlane = Vec4f(0.0f, 0.0f, 0.0f, 1.0f); angle_t angle1, angle2;
} if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2))
else if(polyportal->PortalPlane == Vec4f(0.0f) || Vec4f::dot(polyportal->PortalPlane, Vec4f((float)v.X, (float)v.Y, 0.0f, 1.0f)) > 0.0f) portalSegments.push_back({ angle1, angle2 });
{
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);
} }
} }
#endif
} }
UVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex); 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.flags = TriUniforms::nearest_filter;
args.uniforms.subsectorDepth = isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth; args.uniforms.subsectorDepth = isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth;
TriVertex *vertices = PolyVertexBuffer::GetVertices(sub->numlines); TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(sub->numlines);
if (!vertices)
return;
if (ceiling) if (ceiling)
{ {
@ -364,21 +332,9 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
if (!isSky) if (!isSky)
{ {
if (!portal) args.SetTexture(tex);
{ args.blendmode = TriBlendMode::Copy;
args.SetTexture(tex); PolyTriangleDrawer::draw(args);
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());
}
} }
else else
{ {
@ -398,9 +354,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan
for (uint32_t i = 0; i < sub->numlines; i++) for (uint32_t i = 0; i < sub->numlines; i++)
{ {
TriVertex *wallvert = PolyVertexBuffer::GetVertices(4); TriVertex *wallvert = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
if (!wallvert)
return;
seg_t *line = &sub->firstline[i]; 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) if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
return; 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(); SaveGlobals();
// To do: get this information from PolyRenderer instead of duplicating the code.. // To do: get this information from PolyRenderer instead of duplicating the code..
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow; const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians(); double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians();
double angx = cos(radPitch); 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::translate((float)-viewpoint.Pos.X, (float)-viewpoint.Pos.Y, (float)-viewpoint.Pos.Z);
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; 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.SetPortalSegments(Segments);
RenderPortal.Render(portalDepth); RenderPortal.Render(portalDepth);

View file

@ -52,7 +52,6 @@ public:
uint32_t StencilValue = 0; uint32_t StencilValue = 0;
std::vector<PolyPortalVertexRange> Shape; std::vector<PolyPortalVertexRange> Shape;
std::vector<PolyPortalSegment> Segments; std::vector<PolyPortalSegment> Segments;
Vec4f PortalPlane = Vec4f(0.0f);
private: private:
void SaveGlobals(); 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.. // Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here..
//R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS); //R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS);
TriVertex *vertices = PolyVertexBuffer::GetVertices(4); TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
if (!vertices)
return;
bool foggy = false; bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4; 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); double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum; 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) 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); 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.SetCoords(line->v1->fPos(), line->v2->fPos(), bottomceilz1, bottomfloorz1, bottomceilz2, bottomfloorz2);
wall.TopZ = bottomceilz1; wall.TopZ = bottomceilz1;
@ -204,9 +205,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane
if (!tex && !Polyportal) if (!tex && !Polyportal)
return; return;
TriVertex *vertices = PolyVertexBuffer::GetVertices(4); TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
if (!vertices)
return;
vertices[0].x = (float)v1.X; vertices[0].x = (float)v1.X;
vertices[0].y = (float)v1.Y; 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 }; DVector2 points[2] = { left, right };
TriVertex *vertices = PolyVertexBuffer::GetVertices(4); TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
if (!vertices)
return;
bool foggy = false; bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4; int actualextralight = foggy ? 0 : viewpoint.extralight << 4;