* undo 'winding sorting' hypothesis
* special depth test rules: 'less than' function becomes 'less or equal' when rendering front-facing polygon pixels against back-facing opaque pixels
This commit is contained in:
StapleButter 2017-07-06 18:38:13 +02:00
parent b29b128a1b
commit 3aa83ae641
2 changed files with 53 additions and 31 deletions

View File

@ -858,8 +858,7 @@ void SubmitPolygon()
poly->XTop = xtop; poly->XBottom = xbot;
poly->SortKey = (ybot << 8) | ytop;
if (poly->Translucent) poly->SortKey |= 0x20000;
else if (!poly->FacingView) poly->SortKey |= 0x10000;
if (poly->Translucent) poly->SortKey |= 0x10000;
poly->WShift = wshift;
poly->WBuffer = (FlushAttributes & 0x2);
@ -1801,7 +1800,6 @@ bool YSort(Polygon* a, Polygon* b)
{
// polygon sorting rules:
// * opaque polygons come first
// * opaque polygons are sorted by winding, front-facing polygons come first
// * polygons with lower bottom Y come first
// * upon equal bottom Y, polygons with lower top Y come first
// * upon equal bottom AND top Y, original ordering is used

View File

@ -50,6 +50,7 @@ u32 AttrBuffer[BufferSize * 2];
// bit15: fog enable
// bit24-29: polygon ID
// bit30: translucent flag
// bit31: backfacing flag
u8 StencilBuffer[256*2];
bool PrevIsShadowMask;
@ -655,18 +656,39 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
}
}
template<bool func_equal>
bool DepthTest(s32 oldz, s32 z)
// depth test is 'less or equal' instead of 'less than' under the following conditions:
// * when drawing a front-facing pixel over an opaque back-facing pixel
// * when drawing wireframe edges, under certain conditions (TODO)
bool DepthTest_Equal(s32 dstz, s32 z, u32 dstattr)
{
if (func_equal)
s32 diff = dstz - z;
if ((u32)(diff + 0xFF) <= 0x1FE) // range is +-0xFF
return true;
return false;
}
bool DepthTest_LessThan(s32 dstz, s32 z, u32 dstattr)
{
if (z < dstz)
return true;
return false;
}
bool DepthTest_LessThan_FrontFacing(s32 dstz, s32 z, u32 dstattr)
{
if ((dstattr >> 30) == 0x2) // opaque, back facing
{
s32 diff = oldz - z;
if ((u32)(diff + 0xFF) <= 0x1FE) // range is +-0xFF
if (z <= dstz)
return true;
}
else
if (z < oldz)
return true;
{
if (z < dstz)
return true;
}
return false;
}
@ -920,14 +942,19 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
{
Polygon* polygon = rp->PolyData;
u32 polyattr = (polygon->Attr & 0x3F008000);
if (!polygon->FacingView) polyattr |= (1<<31);
u32 polyalpha = (polygon->Attr >> 16) & 0x1F;
bool wireframe = (polyalpha == 0);
bool (*fnDepthTest)(s32 oldz, s32 z);
bool (*fnDepthTest)(s32 dstz, s32 z, u32 dstattr);
if (polygon->Attr & (1<<14))
fnDepthTest = DepthTest<true>;
fnDepthTest = DepthTest_Equal;
else if (polygon->FacingView)
fnDepthTest = DepthTest_LessThan_FrontFacing;
else
fnDepthTest = DepthTest<false>;
fnDepthTest = DepthTest_LessThan;
if (polygon->IsShadowMask && !PrevIsShadowMask)
memset(&StencilBuffer[256 * (y&0x1)], 0, 256);
@ -1057,7 +1084,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
for (; x < xlimit; x++)
{
u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x;
u32 attr = (polygon->Attr & 0x3F008000);
u32 attr = polyattr;
// check stencil buffer for shadows
if (polygon->IsShadow)
@ -1069,6 +1096,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
interpX.SetX(x);
s32 z = interpX.InterpolateZ(zl, zr, polygon->WBuffer);
u32 dstattr = AttrBuffer[pixeladdr];
if (polygon->IsShadowMask)
{
@ -1085,22 +1113,20 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
}
}
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr))
StencilBuffer[256*(y&0x1) + x] = 1;
continue;
}
u32 dstattr = AttrBuffer[pixeladdr];
// if depth test against the topmost pixel fails, test
// against the pixel underneath
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr))
{
if (!(dstattr & 0x3)) continue;
pixeladdr += BufferSize;
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr]))
continue;
}
@ -1187,7 +1213,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
else for (; x < xlimit; x++)
{
u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x;
u32 attr = (polygon->Attr & 0x3F008000);
u32 attr = polyattr;
// check stencil buffer for shadows
if (polygon->IsShadow)
@ -1199,28 +1225,27 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
interpX.SetX(x);
s32 z = interpX.InterpolateZ(zl, zr, polygon->WBuffer);
u32 dstattr = AttrBuffer[pixeladdr];
if (polygon->IsShadowMask)
{
// for shadow masks: set stencil bits where the depth test fails.
// draw nothing.
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr))
StencilBuffer[256*(y&0x1) + x] = 1;
continue;
}
u32 dstattr = AttrBuffer[pixeladdr];
// if depth test against the topmost pixel fails, test
// against the pixel underneath
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr))
{
if (!(dstattr & 0x3)) continue;
pixeladdr += BufferSize;
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr]))
continue;
}
@ -1277,7 +1302,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
for (; x < xlimit; x++)
{
u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x;
u32 attr = (polygon->Attr & 0x3F008000);
u32 attr = polyattr;
// check stencil buffer for shadows
if (polygon->IsShadow)
@ -1289,6 +1314,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
interpX.SetX(x);
s32 z = interpX.InterpolateZ(zl, zr, polygon->WBuffer);
u32 dstattr = AttrBuffer[pixeladdr];
if (polygon->IsShadowMask)
{
@ -1305,22 +1331,20 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
}
}
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr))
StencilBuffer[256*(y&0x1) + x] = 1;
continue;
}
u32 dstattr = AttrBuffer[pixeladdr];
// if depth test against the topmost pixel fails, test
// against the pixel underneath
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr))
{
if (!(dstattr & 0x3)) continue;
pixeladdr += BufferSize;
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr]))
continue;
}