aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStapleButter <thetotalworm@gmail.com>2017-07-06 18:38:13 +0200
committerStapleButter <thetotalworm@gmail.com>2017-07-06 18:38:13 +0200
commit3aa83ae6418efb01a53d40f07db9780a83d106fa (patch)
tree15238bf35f90d3c505e71d5e646f57e537f9cc1f
parentb29b128a1b696509f05fa7df2cb27740aa7b4389 (diff)
3D:
* 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
-rw-r--r--src/GPU3D.cpp4
-rw-r--r--src/GPU3D_Soft.cpp80
2 files changed, 53 insertions, 31 deletions
diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index e04eaec..ed928d8 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -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
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index 7d424e2..e7cf542 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -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)
+{
+ 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 (func_equal)
+ 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;
}