* perspective-correct Z interpolation
* fix depth buffering. support W-buffer mode. * 3D/2D blending. doesn't do much yet, but the code is here.
This commit is contained in:
parent
ed385ce0f5
commit
72209c51f9
41
GPU2D.cpp
41
GPU2D.cpp
|
@ -55,7 +55,6 @@
|
||||||
// 3D/2D blending rules
|
// 3D/2D blending rules
|
||||||
// * if destination selected as 2nd target:
|
// * if destination selected as 2nd target:
|
||||||
// blending is applied instead of the selected color effect, using full 5bit alpha from 3D layer
|
// blending is applied instead of the selected color effect, using full 5bit alpha from 3D layer
|
||||||
// (or 6bit alpha? TODO: check it)
|
|
||||||
// this even if the selected color effect is 'none'.
|
// this even if the selected color effect is 'none'.
|
||||||
// apparently this works even if BG0 isn't selected as 1st target
|
// apparently this works even if BG0 isn't selected as 1st target
|
||||||
// * if BG0 is selected as 1st target, destination not selected as 2nd target:
|
// * if BG0 is selected as 1st target, destination not selected as 2nd target:
|
||||||
|
@ -766,6 +765,32 @@ void GPU2D::DrawScanline_Mode1(u32 line, u32* dst)
|
||||||
evb = EVB;
|
evb = EVB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((flag1 & 0x40) && (BlendCnt & ((val2 >> 16) & 0xFF00)))
|
||||||
|
{
|
||||||
|
// 3D layer blending
|
||||||
|
|
||||||
|
eva = (flag1 & 0x1F) + 1;
|
||||||
|
evb = 32 - eva;
|
||||||
|
|
||||||
|
u32 r = (((val1 & 0x00003F) * eva) + ((val2 & 0x00003F) * evb)) >> 5;
|
||||||
|
u32 g = ((((val1 & 0x003F00) * eva) + ((val2 & 0x003F00) * evb)) >> 5) & 0x007F00;
|
||||||
|
u32 b = ((((val1 & 0x3F0000) * eva) + ((val2 & 0x3F0000) * evb)) >> 5) & 0x7F0000;
|
||||||
|
|
||||||
|
if (eva <= 16)
|
||||||
|
{
|
||||||
|
r += 0x000001;
|
||||||
|
g += 0x000100;
|
||||||
|
b += 0x010000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r > 0x00003F) r = 0x00003F;
|
||||||
|
if (g > 0x003F00) g = 0x003F00;
|
||||||
|
if (b > 0x3F0000) b = 0x3F0000;
|
||||||
|
|
||||||
|
dst[i] = r | g | b | 0xFF000000;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if (BlendCnt & flag1)
|
else if (BlendCnt & flag1)
|
||||||
{
|
{
|
||||||
if ((bldcnteffect == 1) && (BlendCnt & ((val2 >> 16) & 0xFF00)))
|
if ((bldcnteffect == 1) && (BlendCnt & ((val2 >> 16) & 0xFF00)))
|
||||||
|
@ -848,20 +873,14 @@ void GPU2D::DrawBG_3D(u32 line, u32* dst)
|
||||||
{
|
{
|
||||||
// TODO: scroll, etc
|
// TODO: scroll, etc
|
||||||
|
|
||||||
u8* src = GPU3D::GetLine(line);
|
u32* src = GPU3D::GetLine(line);
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
{
|
{
|
||||||
u8 r = *src++;
|
u32 c = src[i];
|
||||||
u8 g = *src++;
|
if ((c >> 24) == 0) continue;
|
||||||
u8 b = *src++;
|
|
||||||
u8 a = *src++;
|
|
||||||
if (a == 0) continue;
|
|
||||||
|
|
||||||
// TODO: blending
|
|
||||||
// alpha is 6bit too....?
|
|
||||||
|
|
||||||
dst[i+256] = dst[i];
|
dst[i+256] = dst[i];
|
||||||
dst[i] = r | (g << 8) | (b << 16) | 0x01000000;
|
dst[i] = c | 0x40000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
GPU3D.cpp
15
GPU3D.cpp
|
@ -50,6 +50,8 @@
|
||||||
// formula for clear depth: (GBAtek is wrong there)
|
// formula for clear depth: (GBAtek is wrong there)
|
||||||
// clearZ = (val * 0x200) + 0x1FF;
|
// clearZ = (val * 0x200) + 0x1FF;
|
||||||
// if (clearZ >= 0x010000 && clearZ < 0xFFFFFF) clearZ++;
|
// if (clearZ >= 0x010000 && clearZ < 0xFFFFFF) clearZ++;
|
||||||
|
//
|
||||||
|
// alpha is 5-bit
|
||||||
|
|
||||||
|
|
||||||
namespace GPU3D
|
namespace GPU3D
|
||||||
|
@ -195,6 +197,7 @@ u32 NumVertices, NumPolygons;
|
||||||
u32 CurRAMBank;
|
u32 CurRAMBank;
|
||||||
|
|
||||||
u32 FlushRequest;
|
u32 FlushRequest;
|
||||||
|
u32 FlushAttributes, CurFlushAttributes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1307,7 +1310,7 @@ void ExecuteCommand()
|
||||||
TexPalette = ExecParams[0] & 0x1FFF;
|
TexPalette = ExecParams[0] & 0x1FFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x40:
|
case 0x40: // begin polygons
|
||||||
PolygonMode = ExecParams[0] & 0x3;
|
PolygonMode = ExecParams[0] & 0x3;
|
||||||
VertexNum = 0;
|
VertexNum = 0;
|
||||||
VertexNumInPoly = 0;
|
VertexNumInPoly = 0;
|
||||||
|
@ -1316,8 +1319,9 @@ void ExecuteCommand()
|
||||||
CurPolygonAttr = PolygonAttr;
|
CurPolygonAttr = PolygonAttr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x50:
|
case 0x50: // flush
|
||||||
FlushRequest = 1;//0x80000000 | (ExecParams[0] & 0x3);
|
FlushRequest = 1;
|
||||||
|
FlushAttributes = ExecParams[0] & 0x3;
|
||||||
CycleCount = 392;
|
CycleCount = 392;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1383,7 +1387,7 @@ void VBlank()
|
||||||
{
|
{
|
||||||
if (FlushRequest)
|
if (FlushRequest)
|
||||||
{
|
{
|
||||||
SoftRenderer::RenderFrame(CurVertexRAM, CurPolygonRAM, NumPolygons);
|
SoftRenderer::RenderFrame(CurFlushAttributes, CurVertexRAM, CurPolygonRAM, NumPolygons);
|
||||||
|
|
||||||
CurRAMBank = CurRAMBank?0:1;
|
CurRAMBank = CurRAMBank?0:1;
|
||||||
CurVertexRAM = &VertexRAM[CurRAMBank ? 6144 : 0];
|
CurVertexRAM = &VertexRAM[CurRAMBank ? 6144 : 0];
|
||||||
|
@ -1393,10 +1397,11 @@ void VBlank()
|
||||||
NumPolygons = 0;
|
NumPolygons = 0;
|
||||||
|
|
||||||
FlushRequest = 0;
|
FlushRequest = 0;
|
||||||
|
CurFlushAttributes = FlushAttributes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* GetLine(int line)
|
u32* GetLine(int line)
|
||||||
{
|
{
|
||||||
return SoftRenderer::GetLine(line);
|
return SoftRenderer::GetLine(line);
|
||||||
}
|
}
|
||||||
|
|
6
GPU3D.h
6
GPU3D.h
|
@ -66,7 +66,7 @@ void CheckFIFOIRQ();
|
||||||
void CheckFIFODMA();
|
void CheckFIFODMA();
|
||||||
|
|
||||||
void VBlank();
|
void VBlank();
|
||||||
u8* GetLine(int line);
|
u32* GetLine(int line);
|
||||||
|
|
||||||
u8 Read8(u32 addr);
|
u8 Read8(u32 addr);
|
||||||
u16 Read16(u32 addr);
|
u16 Read16(u32 addr);
|
||||||
|
@ -82,8 +82,8 @@ bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
void RenderFrame(Vertex* vertices, Polygon* polygons, int npolys);
|
void RenderFrame(u32 attr, Vertex* vertices, Polygon* polygons, int npolys);
|
||||||
u8* GetLine(int line);
|
u32* GetLine(int line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace GPU3D
|
||||||
namespace SoftRenderer
|
namespace SoftRenderer
|
||||||
{
|
{
|
||||||
|
|
||||||
u8 ColorBuffer[256*192 * 4];
|
u32 ColorBuffer[256*192];
|
||||||
u32 DepthBuffer[256*192];
|
u32 DepthBuffer[256*192];
|
||||||
|
|
||||||
|
|
||||||
|
@ -248,6 +248,7 @@ void RenderPixel(Polygon* polygon, s32 x, s32 y, s32 z, u8 vr, u8 vg, u8 vb, s16
|
||||||
{
|
{
|
||||||
u32 attr = polygon->Attr;
|
u32 attr = polygon->Attr;
|
||||||
|
|
||||||
|
u32* color = &ColorBuffer[(256*y) + x];
|
||||||
u32* depth = &DepthBuffer[(256*y) + x];
|
u32* depth = &DepthBuffer[(256*y) + x];
|
||||||
|
|
||||||
bool passdepth = false;
|
bool passdepth = false;
|
||||||
|
@ -287,18 +288,16 @@ void RenderPixel(Polygon* polygon, s32 x, s32 y, s32 z, u8 vr, u8 vg, u8 vb, s16
|
||||||
b = vb;
|
b = vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* pixel = &ColorBuffer[((256*y) + x) * 4];
|
u32 a = 31; // TODO
|
||||||
pixel[0] = r;
|
|
||||||
pixel[1] = g;
|
*color = r | (g << 8) | (b << 16) | (a << 24);
|
||||||
pixel[2] = b;
|
|
||||||
pixel[3] = 31; // TODO: alpha
|
|
||||||
|
|
||||||
// TODO: optional update for translucent pixels
|
// TODO: optional update for translucent pixels
|
||||||
if (z > 0xFFFFFF) z = 0xFFFFFF;
|
if (z > 0xFFFFFF) z = 0xFFFFFF;
|
||||||
*depth = z;
|
*depth = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPolygon(Polygon* polygon)
|
void RenderPolygon(Polygon* polygon, u32 wbuffer)
|
||||||
{
|
{
|
||||||
int nverts = polygon->NumVertices;
|
int nverts = polygon->NumVertices;
|
||||||
bool isline = false;
|
bool isline = false;
|
||||||
|
@ -316,24 +315,22 @@ void RenderPolygon(Polygon* polygon)
|
||||||
|
|
||||||
if (!vtx->ViewportTransformDone)
|
if (!vtx->ViewportTransformDone)
|
||||||
{
|
{
|
||||||
s32 posX, posY, posZ, posW;
|
s32 posX, posY, posZ;
|
||||||
s32 w = vtx->Position[3];
|
s32 w = vtx->Position[3];
|
||||||
if (w == 0)
|
if (w == 0)
|
||||||
{
|
{
|
||||||
posX = 0;
|
posX = 0;
|
||||||
posY = 0;
|
posY = 0;
|
||||||
posZ = 0;
|
posZ = 0;
|
||||||
posW = 0x1000;
|
w = 0x1000;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
posX = ((s64)vtx->Position[0] << 12) / w;
|
posX = ((s64)vtx->Position[0] << 12) / w;
|
||||||
posY = ((s64)vtx->Position[1] << 12) / w;
|
posY = ((s64)vtx->Position[1] << 12) / w;
|
||||||
|
|
||||||
// TODO: W-buffering
|
if (wbuffer) posZ = w;
|
||||||
posZ = (((s64)vtx->Position[2] * 0x800000) / w) + 0x7FFCFF;
|
else posZ = (((s64)vtx->Position[2] * 0x800000) / w) + 0x7FFEFF;
|
||||||
|
|
||||||
posW = w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 scrX = (((posX + 0x1000) * Viewport[2]) >> 13) + Viewport[0];
|
s32 scrX = (((posX + 0x1000) * Viewport[2]) >> 13) + Viewport[0];
|
||||||
|
@ -349,7 +346,7 @@ void RenderPolygon(Polygon* polygon)
|
||||||
vtx->FinalPosition[0] = scrX;
|
vtx->FinalPosition[0] = scrX;
|
||||||
vtx->FinalPosition[1] = scrY;
|
vtx->FinalPosition[1] = scrY;
|
||||||
vtx->FinalPosition[2] = posZ;
|
vtx->FinalPosition[2] = posZ;
|
||||||
vtx->FinalPosition[3] = posW;
|
vtx->FinalPosition[3] = w;
|
||||||
|
|
||||||
vtx->FinalColor[0] = vtx->Color[0] >> 12;
|
vtx->FinalColor[0] = vtx->Color[0] >> 12;
|
||||||
if (vtx->FinalColor[0]) vtx->FinalColor[0] = ((vtx->FinalColor[0] << 4) + 0xF);
|
if (vtx->FinalColor[0]) vtx->FinalColor[0] = ((vtx->FinalColor[0] << 4) + 0xF);
|
||||||
|
@ -471,6 +468,8 @@ void RenderPolygon(Polygon* polygon)
|
||||||
// seems vertical slopes are interpolated starting from the bottom and not the top. maybe.
|
// seems vertical slopes are interpolated starting from the bottom and not the top. maybe.
|
||||||
// also seems lfactor/rfactor are rounded
|
// also seems lfactor/rfactor are rounded
|
||||||
|
|
||||||
|
// TODO: the calculations can be simplified
|
||||||
|
|
||||||
if (vlnext->FinalPosition[1] == vlcur->FinalPosition[1])
|
if (vlnext->FinalPosition[1] == vlcur->FinalPosition[1])
|
||||||
lfactor = 0;
|
lfactor = 0;
|
||||||
else
|
else
|
||||||
|
@ -503,12 +502,6 @@ void RenderPolygon(Polygon* polygon)
|
||||||
continue; // hax
|
continue; // hax
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 zl = vlcur->FinalPosition[2] + (((s64)(vlnext->FinalPosition[2] - vlcur->FinalPosition[2]) * lfactor) >> 12);
|
|
||||||
s32 zr = vrcur->FinalPosition[2] + (((s64)(vrnext->FinalPosition[2] - vrcur->FinalPosition[2]) * rfactor) >> 12);
|
|
||||||
|
|
||||||
//s32 wl = vlcur->FinalPosition[3] + (((s64)(vlnext->FinalPosition[3] - vlcur->FinalPosition[3]) * lfactor) >> 12);
|
|
||||||
//s32 wr = vrcur->FinalPosition[3] + (((s64)(vrnext->FinalPosition[3] - vrcur->FinalPosition[3]) * rfactor) >> 12);
|
|
||||||
|
|
||||||
s64 perspfactorl1 = ((s64)(0x1000 - lfactor) * vlnext->FinalPosition[3]) >> 12;
|
s64 perspfactorl1 = ((s64)(0x1000 - lfactor) * vlnext->FinalPosition[3]) >> 12;
|
||||||
s64 perspfactorl2 = ((s64)lfactor * vlcur->FinalPosition[3]) >> 12;
|
s64 perspfactorl2 = ((s64)lfactor * vlcur->FinalPosition[3]) >> 12;
|
||||||
s64 perspfactorr1 = ((s64)(0x1000 - rfactor) * vrnext->FinalPosition[3]) >> 12;
|
s64 perspfactorr1 = ((s64)(0x1000 - rfactor) * vrnext->FinalPosition[3]) >> 12;
|
||||||
|
@ -525,6 +518,9 @@ void RenderPolygon(Polygon* polygon)
|
||||||
perspfactorr2 = 0;
|
perspfactorr2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 zl = ((perspfactorl1 * vlcur->FinalPosition[2]) + (perspfactorl2 * vlnext->FinalPosition[2])) / (perspfactorl1 + perspfactorl2);
|
||||||
|
s32 zr = ((perspfactorr1 * vrcur->FinalPosition[2]) + (perspfactorr2 * vrnext->FinalPosition[2])) / (perspfactorr1 + perspfactorr2);
|
||||||
|
|
||||||
s32 wl = ((perspfactorl1 * vlcur->FinalPosition[3]) + (perspfactorl2 * vlnext->FinalPosition[3])) / (perspfactorl1 + perspfactorl2);
|
s32 wl = ((perspfactorl1 * vlcur->FinalPosition[3]) + (perspfactorl2 * vlnext->FinalPosition[3])) / (perspfactorl1 + perspfactorl2);
|
||||||
s32 wr = ((perspfactorr1 * vrcur->FinalPosition[3]) + (perspfactorr2 * vrnext->FinalPosition[3])) / (perspfactorr1 + perspfactorr2);
|
s32 wr = ((perspfactorr1 * vrcur->FinalPosition[3]) + (perspfactorr2 * vrnext->FinalPosition[3])) / (perspfactorr1 + perspfactorr2);
|
||||||
|
|
||||||
|
@ -548,17 +544,15 @@ void RenderPolygon(Polygon* polygon)
|
||||||
if (xl > 255) continue;
|
if (xl > 255) continue;
|
||||||
|
|
||||||
//s32 xdiv = 0x1000 / (xr - xl);
|
//s32 xdiv = 0x1000 / (xr - xl);
|
||||||
|
//s32 xdiv = 0x100000 / (xr - xl);
|
||||||
|
|
||||||
for (s32 x = xl; x < xr; x++)
|
for (s32 x = xl; x < xr; x++)
|
||||||
{
|
{
|
||||||
//if (x!=xl && x!=(xr-1)) continue;
|
//if (x!=xl && x!=(xr-1)) continue;
|
||||||
s32 xfactor = ((x - xl) << 12) / (xr - xl);
|
s32 xfactor = ((x - xl) << 12) / (xr - xl);
|
||||||
//s32 xfactor = (x - xl) * xdiv;
|
//s32 xfactor = (x - xl) * xdiv;
|
||||||
|
//s32 xfactor = ((x - xl) * xdiv) >> 8;
|
||||||
|
|
||||||
s32 z = zl + (((s64)(zr - zl) * xfactor) >> 12);
|
|
||||||
//z = wl + (((s64)(wr - wl) * xfactor) >> 12);
|
|
||||||
//z -= 0x1FF;
|
|
||||||
//if (z < 0) z = 0;
|
|
||||||
|
|
||||||
s32 perspfactor1 = ((s64)(0x1000 - xfactor) * wr) >> 12;
|
s32 perspfactor1 = ((s64)(0x1000 - xfactor) * wr) >> 12;
|
||||||
s32 perspfactor2 = ((s64)xfactor * wl) >> 12;
|
s32 perspfactor2 = ((s64)xfactor * wl) >> 12;
|
||||||
|
@ -569,7 +563,7 @@ void RenderPolygon(Polygon* polygon)
|
||||||
perspfactor2 = 0;
|
perspfactor2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//z = 0x1000000 / (perspfactor1 + perspfactor2);
|
s32 z = ((perspfactor1 * (s64)zl) + (perspfactor2 * (s64)zr)) / (perspfactor1 + perspfactor2);
|
||||||
|
|
||||||
// possible optimization: only do color interpolation if the depth test passes
|
// possible optimization: only do color interpolation if the depth test passes
|
||||||
u32 vr = ((perspfactor1 * rl) + (perspfactor2 * rr)) / (perspfactor1 + perspfactor2);
|
u32 vr = ((perspfactor1 * rl) + (perspfactor2 * rr)) / (perspfactor1 + perspfactor2);
|
||||||
|
@ -579,46 +573,31 @@ void RenderPolygon(Polygon* polygon)
|
||||||
s16 s = ((perspfactor1 * (s64)sl) + (perspfactor2 * (s64)sr)) / (perspfactor1 + perspfactor2);
|
s16 s = ((perspfactor1 * (s64)sl) + (perspfactor2 * (s64)sr)) / (perspfactor1 + perspfactor2);
|
||||||
s16 t = ((perspfactor1 * (s64)tl) + (perspfactor2 * (s64)tr)) / (perspfactor1 + perspfactor2);
|
s16 t = ((perspfactor1 * (s64)tl) + (perspfactor2 * (s64)tr)) / (perspfactor1 + perspfactor2);
|
||||||
|
|
||||||
//printf("y=%d x=%d: s=%04X t=%04X\n", y, x, s, t);
|
|
||||||
|
|
||||||
RenderPixel(polygon, x, y, z, vr>>3, vg>>3, vb>>3, s, t);
|
RenderPixel(polygon, x, y, z, vr>>3, vg>>3, vb>>3, s, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG CODE
|
|
||||||
/*for (int i = 0; i < nverts; i++)
|
|
||||||
{
|
|
||||||
s32 x = scrcoords[i][0];
|
|
||||||
s32 y = scrcoords[i][1];
|
|
||||||
|
|
||||||
u8* pixel = &ColorBuffer[((256*y) + x) * 4];
|
|
||||||
pixel[0] = 63;
|
|
||||||
pixel[1] = 63;
|
|
||||||
pixel[2] = 63;
|
|
||||||
pixel[3] = 31;
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderFrame(Vertex* vertices, Polygon* polygons, int npolys)
|
void RenderFrame(u32 attr, Vertex* vertices, Polygon* polygons, int npolys)
|
||||||
{
|
{
|
||||||
// TODO: render translucent polygons last
|
// TODO: render translucent polygons last
|
||||||
|
|
||||||
// TODO proper clear color/depth support!
|
// TODO proper clear color/depth support!
|
||||||
for (int i = 0; i < 256*192; i++)
|
for (int i = 0; i < 256*192; i++)
|
||||||
{
|
{
|
||||||
((u32*)ColorBuffer)[i] = 0x00000000;
|
ColorBuffer[i] = 0x00000000;
|
||||||
DepthBuffer[i] = 0xFFFFFF;
|
DepthBuffer[i] = 0xFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < npolys; i++)
|
for (int i = 0; i < npolys; i++)
|
||||||
{
|
{
|
||||||
RenderPolygon(&polygons[i]);
|
RenderPolygon(&polygons[i], attr&0x2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* GetLine(int line)
|
u32* GetLine(int line)
|
||||||
{
|
{
|
||||||
return &ColorBuffer[line * 256 * 4];
|
return &ColorBuffer[line * 256];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue