diff options
Diffstat (limited to 'src/GPU3D_Soft.cpp')
-rw-r--r-- | src/GPU3D_Soft.cpp | 95 |
1 files changed, 77 insertions, 18 deletions
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp index 8f7d041..daf5cdd 100644 --- a/src/GPU3D_Soft.cpp +++ b/src/GPU3D_Soft.cpp @@ -1,5 +1,5 @@ /* - Copyright 2016-2017 StapleButter + Copyright 2016-2019 StapleButter This file is part of melonDS. @@ -769,11 +769,24 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha // 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) +// +// range is different based on depth-buffering mode +// Z-buffering: +-0x200 +// W-buffering: +-0xFF + +bool DepthTest_Equal_Z(s32 dstz, s32 z, u32 dstattr) +{ + s32 diff = dstz - z; + if ((u32)(diff + 0x200) <= 0x400) + return true; + + return false; +} -bool DepthTest_Equal(s32 dstz, s32 z, u32 dstattr) +bool DepthTest_Equal_W(s32 dstz, s32 z, u32 dstattr) { s32 diff = dstz - z; - if ((u32)(diff + 0xFF) <= 0x1FE) // range is +-0xFF + if ((u32)(diff + 0xFF) <= 0x1FE) return true; return false; @@ -1099,7 +1112,7 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y) bool (*fnDepthTest)(s32 dstz, s32 z, u32 dstattr); if (polygon->Attr & (1<<14)) - fnDepthTest = DepthTest_Equal; + fnDepthTest = polygon->WBuffer ? DepthTest_Equal_W : DepthTest_Equal_Z; else if (polygon->FacingView) fnDepthTest = DepthTest_LessThan_FrontFacing; else @@ -1213,7 +1226,9 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y) // part 1: left edge edge = yedge | 0x1; - xlimit = xstart+l_edgelen; if (xlimit > 256) xlimit = 256; + xlimit = xstart+l_edgelen; + if (xlimit > xend+1) xlimit = xend+1; + if (xlimit > 256) xlimit = 256; for (; x < xlimit; x++) { @@ -1229,12 +1244,21 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y) continue; if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr)) - StencilBuffer[256*(y&0x1) + x] = 1; + StencilBuffer[256*(y&0x1) + x] |= 0x1; + + if (dstattr & 0x3) + { + pixeladdr += BufferSize; + if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr])) + StencilBuffer[256*(y&0x1) + x] |= 0x2; + } } // part 2: polygon inside edge = yedge; - xlimit = xend-r_edgelen+1; if (xlimit > 256) xlimit = 256; + xlimit = xend-r_edgelen+1; + if (xlimit > xend+1) xlimit = xend+1; + if (xlimit > 256) xlimit = 256; if (wireframe && !edge) x = xlimit; else for (; x < xlimit; x++) { @@ -1247,11 +1271,19 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y) if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr)) StencilBuffer[256*(y&0x1) + x] = 1; + + if (dstattr & 0x3) + { + pixeladdr += BufferSize; + if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr])) + StencilBuffer[256*(y&0x1) + x] |= 0x2; + } } // part 3: right edge edge = yedge | 0x2; - xlimit = xend+1; if (xlimit > 256) xlimit = 256; + xlimit = xend+1; + if (xlimit > 256) xlimit = 256; for (; x < xlimit; x++) { @@ -1268,6 +1300,13 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y) if (!fnDepthTest(DepthBuffer[pixeladdr], z, dstattr)) StencilBuffer[256*(y&0x1) + x] = 1; + + if (dstattr & 0x3) + { + pixeladdr += BufferSize; + if (!fnDepthTest(DepthBuffer[pixeladdr], z, AttrBuffer[pixeladdr])) + StencilBuffer[256*(y&0x1) + x] |= 0x2; + } } rp->XL = rp->SlopeL.Step(); @@ -1286,7 +1325,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y) bool (*fnDepthTest)(s32 dstz, s32 z, u32 dstattr); if (polygon->Attr & (1<<14)) - fnDepthTest = DepthTest_Equal; + fnDepthTest = polygon->WBuffer ? DepthTest_Equal_W : DepthTest_Equal_Z; else if (polygon->FacingView) fnDepthTest = DepthTest_LessThan_FrontFacing; else @@ -1415,7 +1454,9 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y) // part 1: left edge edge = yedge | 0x1; - xlimit = xstart+l_edgelen; if (xlimit > 256) xlimit = 256; + xlimit = xstart+l_edgelen; + if (xlimit > xend+1) xlimit = xend+1; + if (xlimit > 256) xlimit = 256; if (l_edgecov & (1<<31)) { xcov = (l_edgecov >> 12) & 0x3FF; @@ -1425,18 +1466,23 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y) for (; x < xlimit; x++) { u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; + u32 dstattr = AttrBuffer[pixeladdr]; // check stencil buffer for shadows if (polygon->IsShadow) { - if (StencilBuffer[256*(y&0x1) + x] == 0) + u8 stencil = StencilBuffer[256*(y&0x1) + x]; + if (!stencil) continue; + if (!(stencil & 0x1)) + pixeladdr += BufferSize; + if (!(stencil & 0x2)) + dstattr &= ~0x3; // quick way to prevent drawing the shadow under antialiased edges } interpX.SetX(x); s32 z = interpX.InterpolateZ(zl, zr, polygon->WBuffer); - u32 dstattr = AttrBuffer[pixeladdr]; // if depth test against the topmost pixel fails, test // against the pixel underneath @@ -1509,23 +1555,30 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y) // part 2: polygon inside edge = yedge; - xlimit = xend-r_edgelen+1; if (xlimit > 256) xlimit = 256; + xlimit = xend-r_edgelen+1; + if (xlimit > xend+1) xlimit = xend+1; + if (xlimit > 256) xlimit = 256; if (wireframe && !edge) x = xlimit; else for (; x < xlimit; x++) { u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; + u32 dstattr = AttrBuffer[pixeladdr]; // check stencil buffer for shadows if (polygon->IsShadow) { - if (StencilBuffer[256*(y&0x1) + x] == 0) + u8 stencil = StencilBuffer[256*(y&0x1) + x]; + if (!stencil) continue; + if (!(stencil & 0x1)) + pixeladdr += BufferSize; + if (!(stencil & 0x2)) + dstattr &= ~0x3; // quick way to prevent drawing the shadow under antialiased edges } interpX.SetX(x); s32 z = interpX.InterpolateZ(zl, zr, polygon->WBuffer); - u32 dstattr = AttrBuffer[pixeladdr]; // if depth test against the topmost pixel fails, test // against the pixel underneath @@ -1572,7 +1625,8 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y) // part 3: right edge edge = yedge | 0x2; - xlimit = xend+1; if (xlimit > 256) xlimit = 256; + xlimit = xend+1; + if (xlimit > 256) xlimit = 256; if (r_edgecov & (1<<31)) { xcov = (r_edgecov >> 12) & 0x3FF; @@ -1582,18 +1636,23 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y) for (; x < xlimit; x++) { u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; + u32 dstattr = AttrBuffer[pixeladdr]; // check stencil buffer for shadows if (polygon->IsShadow) { - if (StencilBuffer[256*(y&0x1) + x] == 0) + u8 stencil = StencilBuffer[256*(y&0x1) + x]; + if (!stencil) continue; + if (!(stencil & 0x1)) + pixeladdr += BufferSize; + if (!(stencil & 0x2)) + dstattr &= ~0x3; // quick way to prevent drawing the shadow under antialiased edges } interpX.SetX(x); s32 z = interpX.InterpolateZ(zl, zr, polygon->WBuffer); - u32 dstattr = AttrBuffer[pixeladdr]; // if depth test against the topmost pixel fails, test // against the pixel underneath |