* add 'push old pixel down' behavior for antialiasing
* delay final pass (edge/fog/AA) one scanline, required for edgemarking
This commit is contained in:
parent
ae78faf2a7
commit
d3b3255ce3
|
@ -28,9 +28,9 @@ namespace GPU3D
|
||||||
namespace SoftRenderer
|
namespace SoftRenderer
|
||||||
{
|
{
|
||||||
|
|
||||||
u32 ColorBuffer[256*192];
|
u32 ColorBuffer[258*3*194];
|
||||||
u32 DepthBuffer[256*192];
|
u32 DepthBuffer[258*3*194];
|
||||||
u32 AttrBuffer[256*192];
|
u32 AttrBuffer[258*3*194];
|
||||||
|
|
||||||
// attribute buffer:
|
// attribute buffer:
|
||||||
// bit15: fog enable
|
// bit15: fog enable
|
||||||
|
@ -952,6 +952,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
||||||
|
|
||||||
Interpolator interpX(xstart, xend+1, wl, wr, 8);
|
Interpolator interpX(xstart, xend+1, wl, wr, 8);
|
||||||
//printf("%d: edge %d %d, %d %d\n", y, l_edgelen, r_edgelen, l_edgecov, r_edgecov);
|
//printf("%d: edge %d %d, %d %d\n", y, l_edgelen, r_edgelen, l_edgecov, r_edgecov);
|
||||||
|
// TODO: split this based on edge/middle
|
||||||
for (s32 x = xstart; x <= xend; x++)
|
for (s32 x = xstart; x <= xend; x++)
|
||||||
{
|
{
|
||||||
if (x < 0) continue;
|
if (x < 0) continue;
|
||||||
|
@ -968,13 +969,13 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pixeladdr = (y*256) + x;
|
u32 pixeladdr = 258*3 + 1 + (y*258*3) + x;
|
||||||
u32 attr = polygon->Attr & 0x3F008000;
|
u32 attr = polygon->Attr & 0x3F008000;
|
||||||
|
|
||||||
// check stencil buffer for shadows
|
// check stencil buffer for shadows
|
||||||
if (polygon->IsShadow)
|
if (polygon->IsShadow)
|
||||||
{
|
{
|
||||||
if (StencilBuffer[pixeladdr & 0x1FF] == 0)
|
if (StencilBuffer[256*(y&0x1) + x] == 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1000,13 +1001,19 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
|
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
|
||||||
StencilBuffer[pixeladdr & 0x1FF] = 1;
|
StencilBuffer[256*(y&0x1) + x] = 1;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if depth test against the topmost pixel fails, test
|
||||||
|
// against the pixel underneath
|
||||||
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
|
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
|
||||||
continue;
|
{
|
||||||
|
pixeladdr += 258;
|
||||||
|
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
u32 vr = interpX.Interpolate(rl, rr);
|
u32 vr = interpX.Interpolate(rl, rr);
|
||||||
u32 vg = interpX.Interpolate(gl, gr);
|
u32 vg = interpX.Interpolate(gl, gr);
|
||||||
|
@ -1019,13 +1026,11 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
||||||
u8 alpha = color >> 24;
|
u8 alpha = color >> 24;
|
||||||
|
|
||||||
// alpha test
|
// alpha test
|
||||||
// TODO: check alpha test when blending is disabled
|
|
||||||
if (alpha <= RenderAlphaRef) continue;
|
if (alpha <= RenderAlphaRef) continue;
|
||||||
|
|
||||||
if (alpha == 31)
|
if (alpha == 31)
|
||||||
{
|
{
|
||||||
// edge fill rules for opaque pixels
|
// edge fill rules for opaque pixels
|
||||||
// TODO, eventually: antialiasing
|
|
||||||
if (!wireframe)
|
if (!wireframe)
|
||||||
{
|
{
|
||||||
if ((edge & 0x1) && !l_filledge)
|
if ((edge & 0x1) && !l_filledge)
|
||||||
|
@ -1034,6 +1039,14 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// push old pixel down if needed
|
||||||
|
if (edge)
|
||||||
|
{
|
||||||
|
ColorBuffer[pixeladdr+258] = ColorBuffer[pixeladdr];
|
||||||
|
DepthBuffer[pixeladdr+258] = DepthBuffer[pixeladdr];
|
||||||
|
AttrBuffer[pixeladdr+258] = AttrBuffer[pixeladdr];
|
||||||
|
}
|
||||||
|
|
||||||
DepthBuffer[pixeladdr] = z;
|
DepthBuffer[pixeladdr] = z;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1081,6 +1094,14 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
||||||
color = srcR | (srcG << 8) | (srcB << 16) | (dstalpha << 24);
|
color = srcR | (srcG << 8) | (srcB << 16) | (dstalpha << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// push old pixel down if needed
|
||||||
|
if (edge)
|
||||||
|
{
|
||||||
|
ColorBuffer[pixeladdr+258] = ColorBuffer[pixeladdr];
|
||||||
|
DepthBuffer[pixeladdr+258] = DepthBuffer[pixeladdr];
|
||||||
|
AttrBuffer[pixeladdr+258] = AttrBuffer[pixeladdr];
|
||||||
|
}
|
||||||
|
|
||||||
if (polygon->Attr & (1<<11))
|
if (polygon->Attr & (1<<11))
|
||||||
DepthBuffer[pixeladdr] = z;
|
DepthBuffer[pixeladdr] = z;
|
||||||
}
|
}
|
||||||
|
@ -1132,7 +1153,10 @@ void RenderScanline(s32 y, int npolys)
|
||||||
if (y >= polygon->YTop && (y < polygon->YBottom || (y == polygon->YTop && polygon->YBottom == polygon->YTop)))
|
if (y >= polygon->YTop && (y < polygon->YBottom || (y == polygon->YTop && polygon->YBottom == polygon->YTop)))
|
||||||
RenderPolygonScanline(rp, y);
|
RenderPolygonScanline(rp, y);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScanlineFinalPass(s32 y)
|
||||||
|
{
|
||||||
if (RenderDispCnt & (1<<7))
|
if (RenderDispCnt & (1<<7))
|
||||||
{
|
{
|
||||||
// fog
|
// fog
|
||||||
|
@ -1141,6 +1165,9 @@ void RenderScanline(s32 y, int npolys)
|
||||||
// basically, the depth values used in GBAtek need to be
|
// basically, the depth values used in GBAtek need to be
|
||||||
// multiplied by 0x200 to match Z-buffer values
|
// multiplied by 0x200 to match Z-buffer values
|
||||||
|
|
||||||
|
// fog is applied to the topmost two pixels, which is required for
|
||||||
|
// proper antialiasing
|
||||||
|
|
||||||
bool fogcolor = !(RenderDispCnt & (1<<6));
|
bool fogcolor = !(RenderDispCnt & (1<<6));
|
||||||
u32 fogshift = (RenderDispCnt >> 8) & 0xF;
|
u32 fogshift = (RenderDispCnt >> 8) & 0xF;
|
||||||
u32 fogoffset = RenderFogOffset * 0x200;
|
u32 fogoffset = RenderFogOffset * 0x200;
|
||||||
|
@ -1150,72 +1177,106 @@ void RenderScanline(s32 y, int npolys)
|
||||||
u32 fogB = (RenderFogColor >> 9) & 0x3E; if (fogB) fogB++;
|
u32 fogB = (RenderFogColor >> 9) & 0x3E; if (fogB) fogB++;
|
||||||
u32 fogA = (RenderFogColor >> 16) & 0x1F;
|
u32 fogA = (RenderFogColor >> 16) & 0x1F;
|
||||||
|
|
||||||
for (int x = 0; x < 256; x++)
|
for (int i = 0; i < 258*2; i+=258)
|
||||||
{
|
{
|
||||||
u32 pixeladdr = (y*256) + x;
|
for (int x = 0; x < 256; x++)
|
||||||
|
|
||||||
u32 attr = AttrBuffer[pixeladdr];
|
|
||||||
if (!(attr & (1<<15))) continue;
|
|
||||||
|
|
||||||
u32 z = DepthBuffer[pixeladdr];
|
|
||||||
u32 densityid, densityfrac;
|
|
||||||
if (z < fogoffset)
|
|
||||||
{
|
{
|
||||||
densityid = 0;
|
u32 pixeladdr = 258*3 + 1 + (y*258*3) + i + x;
|
||||||
densityfrac = 0;
|
|
||||||
}
|
u32 attr = AttrBuffer[pixeladdr];
|
||||||
else
|
if (!(attr & (1<<15))) continue;
|
||||||
{
|
|
||||||
z = (z - fogoffset) << fogshift;
|
u32 z = DepthBuffer[pixeladdr];
|
||||||
densityid = z >> 19;
|
u32 densityid, densityfrac;
|
||||||
if (densityid >= 32)
|
if (z < fogoffset)
|
||||||
{
|
{
|
||||||
densityid = 32;
|
densityid = 0;
|
||||||
densityfrac = 0;
|
densityfrac = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
densityfrac = z & 0x7FFFF;
|
{
|
||||||
|
z = (z - fogoffset) << fogshift;
|
||||||
|
densityid = z >> 19;
|
||||||
|
if (densityid >= 32)
|
||||||
|
{
|
||||||
|
densityid = 32;
|
||||||
|
densityfrac = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
densityfrac = z & 0x7FFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkme
|
||||||
|
u32 density =
|
||||||
|
((RenderFogDensityTable[densityid] * (0x80000-densityfrac)) +
|
||||||
|
(RenderFogDensityTable[densityid+1] * densityfrac)) >> 19;
|
||||||
|
if (density >= 127) density = 128;
|
||||||
|
|
||||||
|
u32 srccolor = ColorBuffer[pixeladdr];
|
||||||
|
u32 srcR = srccolor & 0x3F;
|
||||||
|
u32 srcG = (srccolor >> 8) & 0x3F;
|
||||||
|
u32 srcB = (srccolor >> 16) & 0x3F;
|
||||||
|
u32 srcA = (srccolor >> 24) & 0x1F;
|
||||||
|
|
||||||
|
if (fogcolor)
|
||||||
|
{
|
||||||
|
srcR = ((fogR * density) + (srcR * (128-density))) >> 7;
|
||||||
|
srcG = ((fogG * density) + (srcG * (128-density))) >> 7;
|
||||||
|
srcB = ((fogB * density) + (srcB * (128-density))) >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (densityid > 0)
|
||||||
|
srcA = ((fogA * density) + (srcA * (128-density))) >> 7;
|
||||||
|
else
|
||||||
|
srcA = ((0x1F * density) + (srcA * (128-density))) >> 7; // checkme
|
||||||
|
|
||||||
|
ColorBuffer[pixeladdr] = srcR | (srcG << 8) | (srcB << 16) | (srcA << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkme
|
|
||||||
u32 density =
|
|
||||||
((RenderFogDensityTable[densityid] * (0x80000-densityfrac)) +
|
|
||||||
(RenderFogDensityTable[densityid+1] * densityfrac)) >> 19;
|
|
||||||
if (density >= 127) density = 128;
|
|
||||||
|
|
||||||
u32 srccolor = ColorBuffer[pixeladdr];
|
|
||||||
u32 srcR = srccolor & 0x3F;
|
|
||||||
u32 srcG = (srccolor >> 8) & 0x3F;
|
|
||||||
u32 srcB = (srccolor >> 16) & 0x3F;
|
|
||||||
u32 srcA = (srccolor >> 24) & 0x1F;
|
|
||||||
|
|
||||||
if (fogcolor)
|
|
||||||
{
|
|
||||||
srcR = ((fogR * density) + (srcR * (128-density))) >> 7;
|
|
||||||
srcG = ((fogG * density) + (srcG * (128-density))) >> 7;
|
|
||||||
srcB = ((fogB * density) + (srcB * (128-density))) >> 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (densityid > 0)
|
|
||||||
srcA = ((fogA * density) + (srcA * (128-density))) >> 7;
|
|
||||||
else
|
|
||||||
srcA = ((0x1F * density) + (srcA * (128-density))) >> 7; // checkme
|
|
||||||
|
|
||||||
ColorBuffer[pixeladdr] = srcR | (srcG << 8) | (srcB << 16) | (srcA << 24);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearBuffers()
|
void ClearBuffers()
|
||||||
{
|
{
|
||||||
|
u32 clearz = ((RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF;
|
||||||
u32 polyid = RenderClearAttr1 & 0x3F000000;
|
u32 polyid = RenderClearAttr1 & 0x3F000000;
|
||||||
|
|
||||||
|
// fill screen borders for edge marking
|
||||||
|
// CHECKME
|
||||||
|
// GBAtek is unsure about the polygon ID, and nothing is said about Z
|
||||||
|
|
||||||
|
for (int x = 0; x < 258; x++)
|
||||||
|
{
|
||||||
|
ColorBuffer[x] = 0;
|
||||||
|
DepthBuffer[x] = clearz;
|
||||||
|
AttrBuffer[x] = polyid;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 258*3; x < 258*3*193; x+=(258*3))
|
||||||
|
{
|
||||||
|
ColorBuffer[x] = 0;
|
||||||
|
DepthBuffer[x] = clearz;
|
||||||
|
AttrBuffer[x] = polyid;
|
||||||
|
ColorBuffer[x+257] = 0;
|
||||||
|
DepthBuffer[x+257] = clearz;
|
||||||
|
AttrBuffer[x+257] = polyid;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 258*3*193; x < 258*3*194; x++)
|
||||||
|
{
|
||||||
|
ColorBuffer[x] = 0;
|
||||||
|
DepthBuffer[x] = clearz;
|
||||||
|
AttrBuffer[x] = polyid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the screen
|
||||||
|
|
||||||
if (RenderDispCnt & (1<<14))
|
if (RenderDispCnt & (1<<14))
|
||||||
{
|
{
|
||||||
u8 xoff = (RenderClearAttr2 >> 16) & 0xFF;
|
u8 xoff = (RenderClearAttr2 >> 16) & 0xFF;
|
||||||
u8 yoff = (RenderClearAttr2 >> 24) & 0xFF;
|
u8 yoff = (RenderClearAttr2 >> 24) & 0xFF;
|
||||||
|
|
||||||
for (int y = 0; y < 256*192; y += 256)
|
for (int y = 0; y < 258*3*192; y+=(258*3))
|
||||||
{
|
{
|
||||||
for (int x = 0; x < 256; x++)
|
for (int x = 0; x < 256; x++)
|
||||||
{
|
{
|
||||||
|
@ -1231,9 +1292,10 @@ void ClearBuffers()
|
||||||
|
|
||||||
u32 z = ((val3 & 0x7FFF) * 0x200) + 0x1FF;
|
u32 z = ((val3 & 0x7FFF) * 0x200) + 0x1FF;
|
||||||
|
|
||||||
ColorBuffer[y+x] = color;
|
u32 pixeladdr = 258*3 + 1 + y + x;
|
||||||
DepthBuffer[y+x] = z;
|
ColorBuffer[pixeladdr] = color;
|
||||||
AttrBuffer[y+x] = polyid | (val3 & 0x8000);
|
DepthBuffer[pixeladdr] = z;
|
||||||
|
AttrBuffer[pixeladdr] = polyid | (val3 & 0x8000);
|
||||||
|
|
||||||
xoff++;
|
xoff++;
|
||||||
}
|
}
|
||||||
|
@ -1251,15 +1313,17 @@ void ClearBuffers()
|
||||||
u32 a = (RenderClearAttr1 >> 16) & 0x1F;
|
u32 a = (RenderClearAttr1 >> 16) & 0x1F;
|
||||||
u32 color = r | (g << 8) | (b << 16) | (a << 24);
|
u32 color = r | (g << 8) | (b << 16) | (a << 24);
|
||||||
|
|
||||||
u32 z = ((RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF;
|
|
||||||
|
|
||||||
polyid |= (RenderClearAttr1 & 0x8000);
|
polyid |= (RenderClearAttr1 & 0x8000);
|
||||||
|
|
||||||
for (int i = 0; i < 256*192; i++)
|
for (int y = 0; y < 258*3*192; y+=(258*3))
|
||||||
{
|
{
|
||||||
ColorBuffer[i] = color;
|
for (int x = 0; x < 256; x++)
|
||||||
DepthBuffer[i] = z;
|
{
|
||||||
AttrBuffer[i] = polyid;
|
u32 pixeladdr = 258*3 + 1 + y + x;
|
||||||
|
ColorBuffer[pixeladdr] = color;
|
||||||
|
DepthBuffer[pixeladdr] = clearz;
|
||||||
|
AttrBuffer[pixeladdr] = polyid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1282,13 +1346,21 @@ void RenderPolygons(bool threaded, Polygon* polygons, int npolys)
|
||||||
SetupPolygon(&PolygonList[j++], &polygons[i]);
|
SetupPolygon(&PolygonList[j++], &polygons[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (s32 y = 0; y < 192; y++)
|
RenderScanline(0, npolys);
|
||||||
|
|
||||||
|
for (s32 y = 1; y < 192; y++)
|
||||||
{
|
{
|
||||||
RenderScanline(y, npolys);
|
RenderScanline(y, npolys);
|
||||||
|
ScanlineFinalPass(y-1);
|
||||||
|
|
||||||
if (threaded)
|
if (threaded)
|
||||||
Platform::Semaphore_Post(Sema_ScanlineCount);
|
Platform::Semaphore_Post(Sema_ScanlineCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScanlineFinalPass(191);
|
||||||
|
|
||||||
|
if (threaded)
|
||||||
|
Platform::Semaphore_Post(Sema_ScanlineCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCount144()
|
void VCount144()
|
||||||
|
@ -1327,7 +1399,7 @@ void RequestLine(int line)
|
||||||
|
|
||||||
u32* GetLine(int line)
|
u32* GetLine(int line)
|
||||||
{
|
{
|
||||||
return &ColorBuffer[line * 256];
|
return &ColorBuffer[line * 258*3 + 258*3 + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue