diff options
author | StapleButter <thetotalworm@gmail.com> | 2017-03-06 23:57:04 +0100 |
---|---|---|
committer | StapleButter <thetotalworm@gmail.com> | 2017-03-06 23:57:04 +0100 |
commit | 72209c51f9db6e1cb7d8f0909d7317454e8b5771 (patch) | |
tree | b49c7b4eb8d0e776b10de5b7d5f06fb5a0b78445 | |
parent | ed385ce0f57fd121342362cbcd01bdda665f6c28 (diff) |
* perspective-correct Z interpolation
* fix depth buffering. support W-buffer mode.
* 3D/2D blending. doesn't do much yet, but the code is here.
-rw-r--r-- | GPU2D.cpp | 41 | ||||
-rw-r--r-- | GPU3D.cpp | 15 | ||||
-rw-r--r-- | GPU3D.h | 6 | ||||
-rw-r--r-- | GPU3D_Soft.cpp | 69 |
4 files changed, 67 insertions, 64 deletions
@@ -55,7 +55,6 @@ // 3D/2D blending rules // * if destination selected as 2nd target: // 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'. // 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: @@ -766,6 +765,32 @@ void GPU2D::DrawScanline_Mode1(u32 line, u32* dst) 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) { if ((bldcnteffect == 1) && (BlendCnt & ((val2 >> 16) & 0xFF00))) @@ -848,20 +873,14 @@ void GPU2D::DrawBG_3D(u32 line, u32* dst) { // TODO: scroll, etc - u8* src = GPU3D::GetLine(line); + u32* src = GPU3D::GetLine(line); for (int i = 0; i < 256; i++) { - u8 r = *src++; - u8 g = *src++; - u8 b = *src++; - u8 a = *src++; - if (a == 0) continue; - - // TODO: blending - // alpha is 6bit too....? + u32 c = src[i]; + if ((c >> 24) == 0) continue; dst[i+256] = dst[i]; - dst[i] = r | (g << 8) | (b << 16) | 0x01000000; + dst[i] = c | 0x40000000; } } @@ -50,6 +50,8 @@ // formula for clear depth: (GBAtek is wrong there) // clearZ = (val * 0x200) + 0x1FF; // if (clearZ >= 0x010000 && clearZ < 0xFFFFFF) clearZ++; +// +// alpha is 5-bit namespace GPU3D @@ -195,6 +197,7 @@ u32 NumVertices, NumPolygons; u32 CurRAMBank; u32 FlushRequest; +u32 FlushAttributes, CurFlushAttributes; @@ -1307,7 +1310,7 @@ void ExecuteCommand() TexPalette = ExecParams[0] & 0x1FFF; break; - case 0x40: + case 0x40: // begin polygons PolygonMode = ExecParams[0] & 0x3; VertexNum = 0; VertexNumInPoly = 0; @@ -1316,8 +1319,9 @@ void ExecuteCommand() CurPolygonAttr = PolygonAttr; break; - case 0x50: - FlushRequest = 1;//0x80000000 | (ExecParams[0] & 0x3); + case 0x50: // flush + FlushRequest = 1; + FlushAttributes = ExecParams[0] & 0x3; CycleCount = 392; break; @@ -1383,7 +1387,7 @@ void VBlank() { if (FlushRequest) { - SoftRenderer::RenderFrame(CurVertexRAM, CurPolygonRAM, NumPolygons); + SoftRenderer::RenderFrame(CurFlushAttributes, CurVertexRAM, CurPolygonRAM, NumPolygons); CurRAMBank = CurRAMBank?0:1; CurVertexRAM = &VertexRAM[CurRAMBank ? 6144 : 0]; @@ -1393,10 +1397,11 @@ void VBlank() NumPolygons = 0; FlushRequest = 0; + CurFlushAttributes = FlushAttributes; } } -u8* GetLine(int line) +u32* GetLine(int line) { return SoftRenderer::GetLine(line); } @@ -66,7 +66,7 @@ void CheckFIFOIRQ(); void CheckFIFODMA(); void VBlank(); -u8* GetLine(int line); +u32* GetLine(int line); u8 Read8(u32 addr); u16 Read16(u32 addr); @@ -82,8 +82,8 @@ bool Init(); void DeInit(); void Reset(); -void RenderFrame(Vertex* vertices, Polygon* polygons, int npolys); -u8* GetLine(int line); +void RenderFrame(u32 attr, Vertex* vertices, Polygon* polygons, int npolys); +u32* GetLine(int line); } diff --git a/GPU3D_Soft.cpp b/GPU3D_Soft.cpp index 0368ee9..b1919f5 100644 --- a/GPU3D_Soft.cpp +++ b/GPU3D_Soft.cpp @@ -27,7 +27,7 @@ namespace GPU3D namespace SoftRenderer { -u8 ColorBuffer[256*192 * 4]; +u32 ColorBuffer[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* color = &ColorBuffer[(256*y) + x]; u32* depth = &DepthBuffer[(256*y) + x]; 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; } - u8* pixel = &ColorBuffer[((256*y) + x) * 4]; - pixel[0] = r; - pixel[1] = g; - pixel[2] = b; - pixel[3] = 31; // TODO: alpha + u32 a = 31; // TODO + + *color = r | (g << 8) | (b << 16) | (a << 24); // TODO: optional update for translucent pixels if (z > 0xFFFFFF) z = 0xFFFFFF; *depth = z; } -void RenderPolygon(Polygon* polygon) +void RenderPolygon(Polygon* polygon, u32 wbuffer) { int nverts = polygon->NumVertices; bool isline = false; @@ -316,24 +315,22 @@ void RenderPolygon(Polygon* polygon) if (!vtx->ViewportTransformDone) { - s32 posX, posY, posZ, posW; + s32 posX, posY, posZ; s32 w = vtx->Position[3]; if (w == 0) { posX = 0; posY = 0; posZ = 0; - posW = 0x1000; + w = 0x1000; } else { posX = ((s64)vtx->Position[0] << 12) / w; posY = ((s64)vtx->Position[1] << 12) / w; - // TODO: W-buffering - posZ = (((s64)vtx->Position[2] * 0x800000) / w) + 0x7FFCFF; - - posW = w; + if (wbuffer) posZ = w; + else posZ = (((s64)vtx->Position[2] * 0x800000) / w) + 0x7FFEFF; } s32 scrX = (((posX + 0x1000) * Viewport[2]) >> 13) + Viewport[0]; @@ -349,7 +346,7 @@ void RenderPolygon(Polygon* polygon) vtx->FinalPosition[0] = scrX; vtx->FinalPosition[1] = scrY; vtx->FinalPosition[2] = posZ; - vtx->FinalPosition[3] = posW; + vtx->FinalPosition[3] = w; vtx->FinalColor[0] = vtx->Color[0] >> 12; 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. // also seems lfactor/rfactor are rounded + // TODO: the calculations can be simplified + if (vlnext->FinalPosition[1] == vlcur->FinalPosition[1]) lfactor = 0; else @@ -503,12 +502,6 @@ void RenderPolygon(Polygon* polygon) 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 perspfactorl2 = ((s64)lfactor * vlcur->FinalPosition[3]) >> 12; s64 perspfactorr1 = ((s64)(0x1000 - rfactor) * vrnext->FinalPosition[3]) >> 12; @@ -525,6 +518,9 @@ void RenderPolygon(Polygon* polygon) 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 wr = ((perspfactorr1 * vrcur->FinalPosition[3]) + (perspfactorr2 * vrnext->FinalPosition[3])) / (perspfactorr1 + perspfactorr2); @@ -548,17 +544,15 @@ void RenderPolygon(Polygon* polygon) if (xl > 255) continue; //s32 xdiv = 0x1000 / (xr - xl); + //s32 xdiv = 0x100000 / (xr - xl); for (s32 x = xl; x < xr; x++) { //if (x!=xl && x!=(xr-1)) continue; s32 xfactor = ((x - xl) << 12) / (xr - xl); //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 perspfactor2 = ((s64)xfactor * wl) >> 12; @@ -569,7 +563,7 @@ void RenderPolygon(Polygon* polygon) 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 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 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); } } - - // 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 proper clear color/depth support! for (int i = 0; i < 256*192; i++) { - ((u32*)ColorBuffer)[i] = 0x00000000; + ColorBuffer[i] = 0x00000000; DepthBuffer[i] = 0xFFFFFF; } 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]; } } |