aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStapleButter <thetotalworm@gmail.com>2017-03-15 00:10:32 +0100
committerStapleButter <thetotalworm@gmail.com>2017-03-15 00:10:32 +0100
commit74f291757add3a6a567f9cb24f1b1968645a455b (patch)
tree7126636053580ac805e9bc9f14ff0d6b0365fe86
parent671050a7f0277f3b1e6250b43943066a4bd43c37 (diff)
less shitty texture mapping. alpha test, sort of.
-rw-r--r--GPU3D.cpp22
-rw-r--r--GPU3D.h3
-rw-r--r--GPU3D_Soft.cpp243
3 files changed, 158 insertions, 110 deletions
diff --git a/GPU3D.cpp b/GPU3D.cpp
index 0e8e45d..60fe733 100644
--- a/GPU3D.cpp
+++ b/GPU3D.cpp
@@ -144,6 +144,8 @@ FIFO<CmdFIFOEntry>* CmdPIPE;
u32 NumCommands, CurCommand, ParamCount, TotalParams;
u32 DispCnt;
+u32 AlphaRef;
+
u32 GXStat;
u32 ExecParams[32];
@@ -233,6 +235,8 @@ void Reset()
TotalParams = 0;
DispCnt = 0;
+ AlphaRef = 0;
+
GXStat = 0;
memset(ExecParams, 0, 32*4);
@@ -425,7 +429,7 @@ void ClipSegment(Vertex* outbuf, Vertex* vout, Vertex* vin)
if (comp != 2) INTERPOLATE(Position[2]);
INTERPOLATE(Position[3]);
mid.Position[comp] = plane*mid.Position[3];
-//printf("clip %d,%d: Y = %08X %08X %08X, %08X %08X\n", comp, plane, vin->Position[1], vout->Position[1], mid.Position[1], (s32)factor_num, factor_den);
+
INTERPOLATE(Color[0]);
INTERPOLATE(Color[1]);
INTERPOLATE(Color[2]);
@@ -1382,6 +1386,8 @@ void VBlank()
{
if (FlushRequest)
{
+ SoftRenderer::DispCnt = DispCnt;
+ SoftRenderer::AlphaRef = AlphaRef;
SoftRenderer::RenderFrame(CurFlushAttributes, CurVertexRAM, CurPolygonRAM, NumPolygons);
CurRAMBank = CurRAMBank?0:1;
@@ -1462,6 +1468,12 @@ u32 Read32(u32 addr)
void Write8(u32 addr, u8 val)
{
+ switch (addr)
+ {
+ case 0x04000340:
+ AlphaRef = val & 0x1F;
+ return;
+ }
}
void Write16(u32 addr, u16 val)
@@ -1472,6 +1484,10 @@ void Write16(u32 addr, u16 val)
DispCnt = val;
return;
+ case 0x04000340:
+ AlphaRef = val & 0x1F;
+ return;
+
case 0x04000350:
ClearAttr1 = (ClearAttr1 & 0xFFFF0000) | val;
return;
@@ -1495,6 +1511,10 @@ void Write32(u32 addr, u32 val)
DispCnt = val & 0xFFFF;
return;
+ case 0x04000340:
+ AlphaRef = val & 0x1F;
+ return;
+
case 0x04000350:
ClearAttr1 = val;
return;
diff --git a/GPU3D.h b/GPU3D.h
index 6d40753..d17cbf5 100644
--- a/GPU3D.h
+++ b/GPU3D.h
@@ -80,6 +80,9 @@ void Write32(u32 addr, u32 val);
namespace SoftRenderer
{
+extern u32 DispCnt;
+extern u32 AlphaRef;
+
bool Init();
void DeInit();
void Reset();
diff --git a/GPU3D_Soft.cpp b/GPU3D_Soft.cpp
index e764595..5c9e7ff 100644
--- a/GPU3D_Soft.cpp
+++ b/GPU3D_Soft.cpp
@@ -27,6 +27,9 @@ namespace GPU3D
namespace SoftRenderer
{
+u32 DispCnt;
+u32 AlphaRef;
+
u32 ColorBuffer[256*192];
u32 DepthBuffer[256*192];
u32 AttrBuffer[256*192];
@@ -43,7 +46,6 @@ bool Init()
void DeInit()
{
- //
}
void Reset()
@@ -301,10 +303,11 @@ u32 RenderPixel(Polygon* polygon, s32 x, s32 y, s32 z, u8 vr, u8 vg, u8 vb, s16
u32 attr = polygon->Attr;
u8 r, g, b, a;
- if (((polygon->TexParam >> 26) & 0x7) != 0)
- {
- // TODO: also take DISP3DCNT into account
+ u32 polyalpha = (polygon->Attr >> 16) & 0x1F;
+ bool wireframe = (polyalpha == 0);
+ if ((DispCnt & (1<<0)) && (((polygon->TexParam >> 26) & 0x7) != 0))
+ {
u8 tr, tg, tb;
u16 tcolor; u8 talpha;
@@ -315,21 +318,20 @@ u32 RenderPixel(Polygon* polygon, s32 x, s32 y, s32 z, u8 vr, u8 vg, u8 vb, s16
tb = (tcolor >> 9) & 0x3E; if (tb) tb++;
// TODO: other blending modes
- /*r = ((tr+1) * (vr+1) - 1) >> 6;
+ r = ((tr+1) * (vr+1) - 1) >> 6;
g = ((tg+1) * (vg+1) - 1) >> 6;
- b = ((tb+1) * (vb+1) - 1) >> 6;*/
- r = tr;
- g = tg;
- b = tb;
+ b = ((tb+1) * (vb+1) - 1) >> 6;
+ a = ((talpha+1) * (polyalpha+1) - 1) >> 5;
}
else
{
r = vr;
g = vg;
b = vb;
+ a = polyalpha;
}
- a = 31;
+ if (wireframe) a = 31;
return r | (g << 8) | (b << 16) | (a << 24);
}
@@ -363,8 +365,6 @@ void RenderPolygon(Polygon* polygon, u32 wbuffer)
}
else
{
- //posX = ((s64)vtx->Position[0] << 12) / w;
- //posY = ((s64)vtx->Position[1] << 12) / w;
posX = (((s64)(vtx->Position[0] + w) * Viewport[2]) / (((s64)w) << 1)) + Viewport[0];
posY = (((s64)(-vtx->Position[1] + w) * Viewport[3]) / (((s64)w) << 1)) + Viewport[1];
@@ -372,9 +372,6 @@ void RenderPolygon(Polygon* polygon, u32 wbuffer)
else posZ = (((s64)vtx->Position[2] * 0x800000) / w) + 0x7FFEFF;
}
- //s32 scrX = (((posX + 0x1000) * Viewport[2]) >> 13) + Viewport[0];
- //s32 scrY = ((0x180000 - ((posY + 0x1000) * Viewport[3])) >> 13) + Viewport[1];
-
if (posX < 0) posX = 0;
else if (posX > 256) posX = 256;
if (posY < 0) posY = 0;
@@ -409,10 +406,6 @@ void RenderPolygon(Polygon* polygon, u32 wbuffer)
ybot = vtx->FinalPosition[1];
vbot = i;
}
-
- //printf("v%d: %d %d %06X, %04X %04X\n",
- // i, vtx->FinalPosition[0], vtx->FinalPosition[1], vtx->FinalPosition[2],
- // vtx->TexCoords[0], vtx->TexCoords[1]);
}
if (ytop > 191) return;
@@ -494,6 +487,7 @@ void RenderPolygon(Polygon* polygon, u32 wbuffer)
else if (rslope) dxr = (rslope > 0) ? 0 : 0x1000;
else dxr = 0x1000;
+ if (ybot > 191) ybot = 191;
for (s32 y = ytop; y < ybot; y++)
{
if (!isline)
@@ -566,43 +560,52 @@ void RenderPolygon(Polygon* polygon, u32 wbuffer)
s32 xstart_int, xend_int;
s32 slope_start, slope_end;
- if (lslope > 0)
+ if (lslope == 0 && rslope == 0 &&
+ polygon->Vertices[lcur]->FinalPosition[0] == polygon->Vertices[rcur]->FinalPosition[0])
{
- xstart = polygon->Vertices[lcur]->FinalPosition[0] + (dxl >> 12);
- if (xstart < polygon->Vertices[lcur]->FinalPosition[0])
- xstart = polygon->Vertices[lcur]->FinalPosition[0];
- else if (xstart > polygon->Vertices[lnext]->FinalPosition[0]-1)
- xstart = polygon->Vertices[lnext]->FinalPosition[0]-1;
- }
- else if (lslope < 0)
- {
- xstart = polygon->Vertices[lcur]->FinalPosition[0] - (dxl >> 12);
- if (xstart < polygon->Vertices[lnext]->FinalPosition[0])
- xstart = polygon->Vertices[lnext]->FinalPosition[0];
- else if (xstart > polygon->Vertices[lcur]->FinalPosition[0]-1)
- xstart = polygon->Vertices[lcur]->FinalPosition[0]-1;
- }
- else
xstart = polygon->Vertices[lcur]->FinalPosition[0];
-
- if (rslope > 0)
- {
- xend = polygon->Vertices[rcur]->FinalPosition[0] + (dxr >> 12);
- if (xend < polygon->Vertices[rcur]->FinalPosition[0])
- xend = polygon->Vertices[rcur]->FinalPosition[0];
- else if (xend > polygon->Vertices[rnext]->FinalPosition[0]-1)
- xend = polygon->Vertices[rnext]->FinalPosition[0]-1;
+ xend = xstart;
}
- else if (rslope < 0)
+ else
{
- xend = polygon->Vertices[rcur]->FinalPosition[0] - (dxr >> 12);
- if (xend < polygon->Vertices[rnext]->FinalPosition[0])
- xend = polygon->Vertices[rnext]->FinalPosition[0];
- else if (xend > polygon->Vertices[rcur]->FinalPosition[0]-1)
- xend = polygon->Vertices[rcur]->FinalPosition[0]-1;
+ if (lslope > 0)
+ {
+ xstart = polygon->Vertices[lcur]->FinalPosition[0] + (dxl >> 12);
+ if (xstart < polygon->Vertices[lcur]->FinalPosition[0])
+ xstart = polygon->Vertices[lcur]->FinalPosition[0];
+ else if (xstart > polygon->Vertices[lnext]->FinalPosition[0]-1)
+ xstart = polygon->Vertices[lnext]->FinalPosition[0]-1;
+ }
+ else if (lslope < 0)
+ {
+ xstart = polygon->Vertices[lcur]->FinalPosition[0] - (dxl >> 12);
+ if (xstart < polygon->Vertices[lnext]->FinalPosition[0])
+ xstart = polygon->Vertices[lnext]->FinalPosition[0];
+ else if (xstart > polygon->Vertices[lcur]->FinalPosition[0]-1)
+ xstart = polygon->Vertices[lcur]->FinalPosition[0]-1;
+ }
+ else
+ xstart = polygon->Vertices[lcur]->FinalPosition[0];
+
+ if (rslope > 0)
+ {
+ xend = polygon->Vertices[rcur]->FinalPosition[0] + (dxr >> 12);
+ if (xend < polygon->Vertices[rcur]->FinalPosition[0])
+ xend = polygon->Vertices[rcur]->FinalPosition[0];
+ else if (xend > polygon->Vertices[rnext]->FinalPosition[0]-1)
+ xend = polygon->Vertices[rnext]->FinalPosition[0]-1;
+ }
+ else if (rslope < 0)
+ {
+ xend = polygon->Vertices[rcur]->FinalPosition[0] - (dxr >> 12);
+ if (xend < polygon->Vertices[rnext]->FinalPosition[0])
+ xend = polygon->Vertices[rnext]->FinalPosition[0];
+ else if (xend > polygon->Vertices[rcur]->FinalPosition[0]-1)
+ xend = polygon->Vertices[rcur]->FinalPosition[0]-1;
+ }
+ else
+ xend = polygon->Vertices[rcur]->FinalPosition[0] - 1;
}
- else
- xend = polygon->Vertices[rcur]->FinalPosition[0] - 1;
// if the left and right edges are swapped, render backwards.
// note: we 'forget' to swap the xmajor flags, on purpose
@@ -631,54 +634,66 @@ void RenderPolygon(Polygon* polygon, u32 wbuffer)
}
// interpolate attributes along Y
+ s64 lfactor1, lfactor2;
+ s64 rfactor1, rfactor2;
- s64 lfactor1 = (vlnext->FinalPosition[1] - y) * vlnext->FinalPosition[3];
- s64 lfactor2 = (y - vlcur->FinalPosition[1]) * vlcur->FinalPosition[3];
- s64 denom = lfactor1 + lfactor2;
- if (denom)
+ if (l_xmajor)
{
- lfactor1 = (lfactor1 << 12) / denom;
- lfactor2 = (lfactor2 << 12) / denom;
+ lfactor1 = (vlnext->FinalPosition[0] - xstart) * vlnext->FinalPosition[3];
+ lfactor2 = (xstart - vlcur->FinalPosition[0]) * vlcur->FinalPosition[3];
}
else
{
+ lfactor1 = (vlnext->FinalPosition[1] - y) * vlnext->FinalPosition[3];
+ lfactor2 = (y - vlcur->FinalPosition[1]) * vlcur->FinalPosition[3];
+ }
+
+ s64 ldenom = lfactor1 + lfactor2;
+ if (ldenom == 0)
+ {
lfactor1 = 0x1000;
lfactor2 = 0;
+ ldenom = 0x1000;
}
- s64 rfactor1 = (vrnext->FinalPosition[1] - y) * vrnext->FinalPosition[3];
- s64 rfactor2 = (y - vrcur->FinalPosition[1]) * vrcur->FinalPosition[3];
- denom = rfactor1 + rfactor2;
- if (denom)
+ if (r_xmajor)
{
- rfactor1 = (rfactor1 << 12) / denom;
- rfactor2 = (rfactor2 << 12) / denom;
+ rfactor1 = (vrnext->FinalPosition[0] - xend+1) * vrnext->FinalPosition[3];
+ rfactor2 = (xend+1 - vrcur->FinalPosition[0]) * vrcur->FinalPosition[3];
}
else
{
+ rfactor1 = (vrnext->FinalPosition[1] - y) * vrnext->FinalPosition[3];
+ rfactor2 = (y - vrcur->FinalPosition[1]) * vrcur->FinalPosition[3];
+ }
+
+ s64 rdenom = rfactor1 + rfactor2;
+ if (rdenom == 0)
+ {
rfactor1 = 0x1000;
rfactor2 = 0;
+ rdenom = 0x1000;
}
- s32 zl = ((lfactor1 * vlcur->FinalPosition[2]) + (lfactor2 * vlnext->FinalPosition[2])) >> 12;
- s32 zr = ((rfactor1 * vrcur->FinalPosition[2]) + (rfactor2 * vrnext->FinalPosition[2])) >> 12;
+ s32 zl = ((lfactor1 * vlcur->FinalPosition[2]) + (lfactor2 * vlnext->FinalPosition[2])) / ldenom;
+ s32 zr = ((rfactor1 * vrcur->FinalPosition[2]) + (rfactor2 * vrnext->FinalPosition[2])) / rdenom;
- s32 wl = ((lfactor1 * vlcur->FinalPosition[3]) + (lfactor2 * vlnext->FinalPosition[3])) >> 12;
- s32 wr = ((rfactor1 * vrcur->FinalPosition[3]) + (rfactor2 * vrnext->FinalPosition[3])) >> 12;
+ s32 wl = ((lfactor1 * vlcur->FinalPosition[3]) + (lfactor2 * vlnext->FinalPosition[3])) / ldenom;
+ s32 wr = ((rfactor1 * vrcur->FinalPosition[3]) + (rfactor2 * vrnext->FinalPosition[3])) / rdenom;
- s32 rl = ((lfactor1 * vlcur->FinalColor[0]) + (lfactor2 * vlnext->FinalColor[0])) >> 12;
- s32 gl = ((lfactor1 * vlcur->FinalColor[1]) + (lfactor2 * vlnext->FinalColor[1])) >> 12;
- s32 bl = ((lfactor1 * vlcur->FinalColor[2]) + (lfactor2 * vlnext->FinalColor[2])) >> 12;
+ s32 rl = ((lfactor1 * vlcur->FinalColor[0]) + (lfactor2 * vlnext->FinalColor[0])) / ldenom;
+ s32 gl = ((lfactor1 * vlcur->FinalColor[1]) + (lfactor2 * vlnext->FinalColor[1])) / ldenom;
+ s32 bl = ((lfactor1 * vlcur->FinalColor[2]) + (lfactor2 * vlnext->FinalColor[2])) / ldenom;
- s32 sl = ((lfactor1 * vlcur->TexCoords[0]) + (lfactor2 * vlnext->TexCoords[0])) >> 12;
- s32 tl = ((lfactor1 * vlcur->TexCoords[1]) + (lfactor2 * vlnext->TexCoords[1])) >> 12;
+ s32 sl = ((lfactor1 * vlcur->TexCoords[0]) + (lfactor2 * vlnext->TexCoords[0])) / ldenom;
+ s32 tl = ((lfactor1 * vlcur->TexCoords[1]) + (lfactor2 * vlnext->TexCoords[1])) / ldenom;
- s32 rr = ((rfactor1 * vrcur->FinalColor[0]) + (rfactor2 * vrnext->FinalColor[0])) >> 12;
- s32 gr = ((rfactor1 * vrcur->FinalColor[1]) + (rfactor2 * vrnext->FinalColor[1])) >> 12;
- s32 br = ((rfactor1 * vrcur->FinalColor[2]) + (rfactor2 * vrnext->FinalColor[2])) >> 12;
+ s32 rr = ((rfactor1 * vrcur->FinalColor[0]) + (rfactor2 * vrnext->FinalColor[0])) / rdenom;
+ s32 gr = ((rfactor1 * vrcur->FinalColor[1]) + (rfactor2 * vrnext->FinalColor[1])) / rdenom;
+ s32 br = ((rfactor1 * vrcur->FinalColor[2]) + (rfactor2 * vrnext->FinalColor[2])) / rdenom;
- s32 sr = ((rfactor1 * vrcur->TexCoords[0]) + (rfactor2 * vrnext->TexCoords[0])) >> 12;
- s32 tr = ((rfactor1 * vrcur->TexCoords[1]) + (rfactor2 * vrnext->TexCoords[1])) >> 12;
+ s32 sr = ((rfactor1 * vrcur->TexCoords[0]) + (rfactor2 * vrnext->TexCoords[0])) / rdenom;
+ s32 tr = ((rfactor1 * vrcur->TexCoords[1]) + (rfactor2 * vrnext->TexCoords[1])) / rdenom;
// calculate edges
s32 l_edgeend, r_edgestart;
@@ -708,9 +723,13 @@ void RenderPolygon(Polygon* polygon, u32 wbuffer)
// * left edge is filled if slope <= 1
// * edges with slope = 0 are always filled
// edges are always filled if the pixels are translucent
-if (y<0 || y>191 || xstart<0 || xend>255) { printf("BAD COORD %d %d %d\n", y, xstart, xend); return; }
+ // in wireframe mode, there are special rules for equal Z (TODO)
+
for (s32 x = xstart; x <= xend; x++)
{
+ if (x < 0) continue;
+ if (x > 255) break;
+
int edge = 0;
if (y == ytop) edge |= 0x4;
else if (y == ybot-1) edge |= 0x8;
@@ -720,47 +739,63 @@ if (y<0 || y>191 || xstart<0 || xend>255) { printf("BAD COORD %d %d %d\n", y, xs
// wireframe polygons. really ugly, but works
if (wireframe && edge==0) continue;
- s64 factor1 = (xend - x) * wr;
+ s64 factor1 = (xend+1 - x) * wr;
s64 factor2 = (x - xstart) * wl;
s64 denom = factor1 + factor2;
- if (denom)
- {
- factor1 = (factor1 << 12) / denom;
- factor2 = (factor2 << 12) / denom;
- }
- else
+ if (denom == 0)
{
factor1 = 0x1000;
factor2 = 0;
+ denom = 0x1000;
}
- s32 z = ((factor1 * zl) + (factor2 * zr)) >> 12;
+ s32 z = ((factor1 * zl) + (factor2 * zr)) / denom;
if (!DepthTest(polygon, x, y, z)) continue;
- u32 vr = ((factor1 * rl) + (factor2 * rr)) >> 12;
- u32 vg = ((factor1 * gl) + (factor2 * gr)) >> 12;
- u32 vb = ((factor1 * bl) + (factor2 * br)) >> 12;
+ u32 vr = ((factor1 * rl) + (factor2 * rr)) / denom;
+ u32 vg = ((factor1 * gl) + (factor2 * gr)) / denom;
+ u32 vb = ((factor1 * bl) + (factor2 * br)) / denom;
- s16 s = ((factor1 * sl) + (factor2 * sr)) >> 12;
- s16 t = ((factor1 * tl) + (factor2 * tr)) >> 12;
+ s16 s = ((factor1 * sl) + (factor2 * sr)) / denom;
+ s16 t = ((factor1 * tl) + (factor2 * tr)) / denom;
u32 color = RenderPixel(polygon, x, y, z, vr>>3, vg>>3, vb>>3, s, t);
u32 attr = 0;
u8 alpha = color >> 24;
- if (alpha == 31 && !wireframe)
+
+ // alpha test
+ if (DispCnt & (1<<2))
{
- if ((edge & 0x1) && slope_start > 0x1000)
- continue;
- if ((edge & 0x2) && (slope_end != 0 && slope_end <= 0x1000))
- continue;
+ if (alpha <= AlphaRef) continue;
}
- // TODO: blending
+ // alpha blending disable
+ // TODO: check alpha test when blending is disabled
+ if (!(DispCnt & (1<<3)))
+ alpha = 31;
+
+ if (alpha == 31)
+ {
+ if (!wireframe)
+ {
+ if ((edge & 0x1) && slope_start > 0x1000)
+ continue;
+ if ((edge & 0x2) && (slope_end != 0 && slope_end <= 0x1000))
+ continue;
+ }
+
+ DepthBuffer[(y*256) + x] = z;
+ }
+ else if (alpha > 0)
+ {
+ //
+
+ // TODO: conditional Z-buffer update
+ DepthBuffer[(y*256) + x] = z;
+ }
- //if (ColorBuffer[(y*256) + x] != 0x1F3F3F3F)
ColorBuffer[(y*256) + x] = color;
- DepthBuffer[(y*256) + x] = z;
AttrBuffer[(y*256) + x] = attr;
}
@@ -769,16 +804,6 @@ if (y<0 || y>191 || xstart<0 || xend>255) { printf("BAD COORD %d %d %d\n", y, xs
if (rslope > 0) dxr += rslope;
else dxr -= rslope;
}
-
- /*for (int i = 0; i < nverts; i++)
- {
- Vertex* vtx = polygon->Vertices[i];
-
- int x = vtx->FinalPosition[0];
- int y = vtx->FinalPosition[1];
- if (x>=0 && x<256 && y>=0 && y<192)
- ColorBuffer[(y*256) + x] = 0x1F3F3F3F;//printf("%d %d -- %08X %08X %08X\n", x, y, vtx->Position[0], vtx->Position[1], vtx->Position[3]);
- }*/
}
void RenderFrame(u32 attr, Vertex* vertices, Polygon* polygons, int npolys)