rework entire fix to do things in a (potentially) more hw accurate way
also remove some tangentially related but kinda dumb code i wrote
This commit is contained in:
parent
36ff3a41b9
commit
5ca5c1a4a1
|
@ -757,6 +757,12 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon*
|
|||
|
||||
s32 zl = rp->SlopeL.Interp.InterpolateZ(polygon->FinalZ[rp->CurVL], polygon->FinalZ[rp->NextVL], polygon->WBuffer);
|
||||
s32 zr = rp->SlopeR.Interp.InterpolateZ(polygon->FinalZ[rp->CurVR], polygon->FinalZ[rp->NextVR], polygon->WBuffer);
|
||||
|
||||
rp->SlopeL.EdgeParams(&l_edgelen, &l_edgecov);
|
||||
rp->SlopeR.EdgeParams(&r_edgelen, &r_edgecov);
|
||||
|
||||
if (rp->SlopeL.XMajor && rp->SlopeL.Negative) xstart -= l_edgelen;
|
||||
if (rp->SlopeR.XMajor && !rp->SlopeR.Negative) xend += r_edgelen;
|
||||
|
||||
// right vertical edges are pushed 1px to the left as long as either:
|
||||
// the left edge slope is not 0, or the span is not 0 pixels wide, and it is not at the leftmost pixel of the screen
|
||||
|
@ -773,11 +779,14 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon*
|
|||
|
||||
interp_start = &rp->SlopeR.Interp;
|
||||
interp_end = &rp->SlopeL.Interp;
|
||||
|
||||
rp->SlopeR.EdgeParams<true>(&l_edgelen, &l_edgecov);
|
||||
rp->SlopeL.EdgeParams<true>(&r_edgelen, &r_edgecov);
|
||||
|
||||
|
||||
std::swap(xstart, xend);
|
||||
|
||||
l_edgelen = 1;
|
||||
r_edgelen = 1;
|
||||
|
||||
// ignore fixing coverage, shadow masks don't use it
|
||||
|
||||
std::swap(wl, wr);
|
||||
std::swap(zl, zr);
|
||||
|
||||
|
@ -806,9 +815,6 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon*
|
|||
interp_start = &rp->SlopeL.Interp;
|
||||
interp_end = &rp->SlopeR.Interp;
|
||||
|
||||
rp->SlopeL.EdgeParams<false>(&l_edgelen, &l_edgecov);
|
||||
rp->SlopeR.EdgeParams<false>(&r_edgelen, &r_edgecov);
|
||||
|
||||
// CHECKME: edge fill rules for unswapped opaque shadow mask polygons
|
||||
if ((gpu3d.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (gpu3d.RenderDispCnt & (1<<3))) || wireframe)
|
||||
{
|
||||
|
@ -982,6 +988,12 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3
|
|||
|
||||
s32 zl = rp->SlopeL.Interp.InterpolateZ(polygon->FinalZ[rp->CurVL], polygon->FinalZ[rp->NextVL], polygon->WBuffer);
|
||||
s32 zr = rp->SlopeR.Interp.InterpolateZ(polygon->FinalZ[rp->CurVR], polygon->FinalZ[rp->NextVR], polygon->WBuffer);
|
||||
|
||||
rp->SlopeL.EdgeParams(&l_edgelen, &l_edgecov);
|
||||
rp->SlopeR.EdgeParams(&r_edgelen, &r_edgecov);
|
||||
|
||||
if (rp->SlopeL.XMajor && rp->SlopeL.Negative) xstart -= l_edgelen;
|
||||
if (rp->SlopeR.XMajor && !rp->SlopeR.Negative) xend += r_edgelen;
|
||||
|
||||
// right vertical edges are pushed 1px to the left as long as either:
|
||||
// the left edge slope is not 0, or the span is not 0 pixels wide, and it is not at the leftmost pixel of the screen
|
||||
|
@ -1003,10 +1015,17 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3
|
|||
interp_start = &rp->SlopeR.Interp;
|
||||
interp_end = &rp->SlopeL.Interp;
|
||||
|
||||
rp->SlopeR.EdgeParams<true>(&l_edgelen, &l_edgecov);
|
||||
rp->SlopeL.EdgeParams<true>(&r_edgelen, &r_edgecov);
|
||||
|
||||
std::swap(xstart, xend);
|
||||
|
||||
l_edgelen = 1;
|
||||
r_edgelen = 1;
|
||||
|
||||
std::swap(l_edgecov, r_edgecov);
|
||||
|
||||
// yes this breaks vertical slopes, blame hw
|
||||
if (!rp->SlopeR.XMajor) l_edgecov = 31-l_edgecov;
|
||||
if (!rp->SlopeL.XMajor) r_edgecov = 31-r_edgecov;
|
||||
|
||||
std::swap(wl, wr);
|
||||
std::swap(zl, zr);
|
||||
|
||||
|
@ -1041,9 +1060,6 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3
|
|||
interp_start = &rp->SlopeL.Interp;
|
||||
interp_end = &rp->SlopeR.Interp;
|
||||
|
||||
rp->SlopeL.EdgeParams<false>(&l_edgelen, &l_edgecov);
|
||||
rp->SlopeR.EdgeParams<false>(&r_edgelen, &r_edgecov);
|
||||
|
||||
// edge fill rules for unswapped opaque edges:
|
||||
// * right edge is filled if slope > 1
|
||||
// * left edge is filled if slope <= 1
|
||||
|
|
|
@ -295,11 +295,11 @@ private:
|
|||
|
||||
XMajor = (Increment > 0x40000);
|
||||
|
||||
if constexpr (side)
|
||||
if (side)
|
||||
{
|
||||
// right
|
||||
|
||||
if (XMajor) dx = Negative ? (0x20000 + 0x40000) : (Increment - 0x20000);
|
||||
if (XMajor) dx = Negative ? (0x20000 + 0x40000) : -0x20000;
|
||||
else if (Increment != 0) dx = Negative ? 0x40000 : 0;
|
||||
else dx = 0;
|
||||
}
|
||||
|
@ -307,27 +307,15 @@ private:
|
|||
{
|
||||
// left
|
||||
|
||||
if (XMajor) dx = Negative ? ((Increment - 0x20000) + 0x40000) : 0x20000;
|
||||
if (XMajor) dx = 0x20000;
|
||||
else if (Increment != 0) dx = Negative ? 0x40000 : 0;
|
||||
else dx = 0;
|
||||
}
|
||||
|
||||
dx += (y - y0) * Increment;
|
||||
|
||||
if (XMajor)
|
||||
{
|
||||
// used for calculating AA coverage
|
||||
xcov_incr = (ylen << 10) / xlen;
|
||||
|
||||
if (side ^ Negative)
|
||||
{
|
||||
dxold = dx;
|
||||
// I dont think the first span can have a gap but
|
||||
// I think its technically correct to do this calc anyway?
|
||||
// could probably be removed as a minor optimization
|
||||
dx &= ~0x1FF;
|
||||
}
|
||||
}
|
||||
// used for calculating AA coverage
|
||||
if (XMajor) xcov_incr = (ylen << 10) / xlen;
|
||||
|
||||
s32 x = XVal();
|
||||
|
||||
|
@ -340,15 +328,7 @@ private:
|
|||
|
||||
constexpr s32 Step()
|
||||
{
|
||||
if (XMajor && (side ^ Negative)) // tl, br = \ (right side end) & tr, bl = / (left side start)
|
||||
{
|
||||
// round dx; required to create gaps in lines like on hw
|
||||
// increment using dxold to make the line not completely borked after rendering a gap
|
||||
dx = (dxold & ~0x1FF) + Increment;
|
||||
dxold += Increment;
|
||||
}
|
||||
else
|
||||
dx += Increment;
|
||||
dx += Increment;
|
||||
|
||||
y++;
|
||||
|
||||
|
@ -363,26 +343,13 @@ private:
|
|||
if (Negative) ret = x0 - (dx >> 18);
|
||||
else ret = x0 + (dx >> 18);
|
||||
|
||||
if (ret < xmin) ret = xmin;
|
||||
else if (ret > xmax) ret = xmax;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<bool swapped>
|
||||
constexpr void EdgeParams_XMajor(s32* length, s32* coverage) const
|
||||
{
|
||||
// only do length calc for right side when swapped as it's
|
||||
// only needed for aa calcs, as actual line spans are broken
|
||||
if constexpr (!swapped || side)
|
||||
{
|
||||
// credit to StrikerX3 for working out this weird rounding nonsense
|
||||
if (side ^ Negative) // tr, bl = / (left side end) & tl br = \ (right side start)
|
||||
// dxold used here to avoid rounding the endpoint
|
||||
*length = (dx >> 18) - (dxold - Increment >> 18);
|
||||
else // tl, br = \ (left side end) & tr, bl = / (right side start)
|
||||
// dx rounded down to create gaps in lines like on hw
|
||||
*length = ((dx & ~0x1FF) + Increment >> 18) - (dx >> 18);
|
||||
}
|
||||
// credit to StrikerX3 for their efforts researching the strange rounding behavior of the "length" calculation
|
||||
*length = (dx & (0x1FF << 9)) + Increment >> 18;
|
||||
|
||||
// for X-major edges, we return the coverage
|
||||
// for the first pixel, and the increment for
|
||||
|
@ -394,49 +361,31 @@ private:
|
|||
|
||||
s32 startcov = (((startx << 10) + 0x1FF) * ylen) / xlen;
|
||||
*coverage = (1<<31) | ((startcov & 0x3FF) << 12) | (xcov_incr & 0x3FF);
|
||||
|
||||
if constexpr (swapped) *length = 1;
|
||||
}
|
||||
|
||||
template<bool swapped>
|
||||
constexpr void EdgeParams_YMajor(s32* length, s32* coverage) const
|
||||
{
|
||||
*length = 1;
|
||||
|
||||
if (Increment == 0)
|
||||
{
|
||||
// for some reason vertical edges' aa values
|
||||
// are inverted too when the edges are swapped
|
||||
if constexpr (swapped)
|
||||
*coverage = 0;
|
||||
else
|
||||
*coverage = 31;
|
||||
}
|
||||
if (Increment == 0) *coverage = 31;
|
||||
else
|
||||
{
|
||||
s32 cov = ((dx >> 9) + (Increment >> 10)) >> 4;
|
||||
if ((cov >> 5) != (dx >> 18)) cov = 31;
|
||||
cov &= 0x1F;
|
||||
if constexpr (swapped)
|
||||
{
|
||||
if (side ^ Negative) cov = 0x1F - cov;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(side ^ Negative)) cov = 0x1F - cov;
|
||||
}
|
||||
|
||||
if (!(side ^ Negative)) cov = 0x1F - cov;
|
||||
|
||||
*coverage = cov;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool swapped>
|
||||
constexpr void EdgeParams(s32* length, s32* coverage) const
|
||||
{
|
||||
if (XMajor)
|
||||
return EdgeParams_XMajor<swapped>(length, coverage);
|
||||
return EdgeParams_XMajor(length, coverage);
|
||||
else
|
||||
return EdgeParams_YMajor<swapped>(length, coverage);
|
||||
return EdgeParams_YMajor(length, coverage);
|
||||
}
|
||||
|
||||
s32 Increment;
|
||||
|
@ -447,7 +396,7 @@ private:
|
|||
private:
|
||||
s32 x0, xmin, xmax;
|
||||
s32 xlen, ylen;
|
||||
s32 dx, dxold;
|
||||
s32 dx;
|
||||
s32 y;
|
||||
|
||||
s32 xcov_incr;
|
||||
|
|
Loading…
Reference in New Issue