aboutsummaryrefslogtreecommitdiff
path: root/src/GPU3D_Soft.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/GPU3D_Soft.cpp')
-rw-r--r--src/GPU3D_Soft.cpp95
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