optimize the 3D renderer somewhat
This commit is contained in:
parent
796e60828c
commit
eb656857d9
|
@ -717,9 +717,8 @@ void SubmitPolygon()
|
|||
poly->FacingView = facingview;
|
||||
|
||||
u32 texfmt = (TexParam >> 26) & 0x7;
|
||||
u32 blendmode = (CurPolygonAttr >> 4) & 0x3;
|
||||
u32 polyalpha = (CurPolygonAttr >> 16) & 0x1F;
|
||||
poly->Translucent = ((texfmt == 1 || texfmt == 6) && (blendmode != 1)) || (polyalpha > 0 && polyalpha < 31);
|
||||
poly->Translucent = ((texfmt == 1 || texfmt == 6) && !(CurPolygonAttr & 0x10)) || (polyalpha > 0 && polyalpha < 31);
|
||||
|
||||
if (LastStripPolygon && clipstart > 0)
|
||||
{
|
||||
|
@ -764,24 +763,29 @@ void SubmitPolygon()
|
|||
}
|
||||
else
|
||||
{
|
||||
// W is normalized, such that all the polygon's W values fit within 16 bits
|
||||
// the viewport transform for X and Y uses the original W values, but
|
||||
// the transform for Z uses the normalized W values
|
||||
// W normalization is applied to separate polygons, even within strips
|
||||
|
||||
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];
|
||||
|
||||
if (FlushAttributes & 0x2) posZ = w;
|
||||
else posZ = (((s64)vtx->Position[2] * 0x800000) / w) + 0x7FFEFF;
|
||||
//if (FlushAttributes & 0x2) posZ = w;
|
||||
//else posZ = (((s64)vtx->Position[2] * 0x800000) / w) + 0x7FFEFF;
|
||||
}
|
||||
|
||||
if (posX < 0) posX = 0;
|
||||
else if (posX > 256) posX = 256;
|
||||
if (posY < 0) posY = 0;
|
||||
else if (posY > 192) posY = 192;
|
||||
if (posZ < 0) posZ = 0;
|
||||
else if (posZ > 0xFFFFFF) posZ = 0xFFFFFF;
|
||||
//if (posZ < 0) posZ = 0;
|
||||
//else if (posZ > 0xFFFFFF) posZ = 0xFFFFFF;
|
||||
|
||||
vtx->FinalPosition[0] = posX;
|
||||
vtx->FinalPosition[1] = posY;
|
||||
vtx->FinalPosition[2] = posZ;
|
||||
vtx->FinalPosition[3] = w;
|
||||
//vtx->FinalPosition[2] = posZ;
|
||||
//vtx->FinalPosition[3] = w;
|
||||
|
||||
vtx->FinalColor[0] = vtx->Color[0] >> 12;
|
||||
if (vtx->FinalColor[0]) vtx->FinalColor[0] = ((vtx->FinalColor[0] << 4) + 0xF);
|
||||
|
@ -792,9 +796,12 @@ void SubmitPolygon()
|
|||
}
|
||||
|
||||
// determine bounds of the polygon
|
||||
// also determine the W shift and normalize W
|
||||
|
||||
u32 vtop = 0, vbot = 0;
|
||||
s32 ytop = 192, ybot = 0;
|
||||
s32 xtop = 256, xbot = 0;
|
||||
u32 wshift = 0;
|
||||
|
||||
for (int i = 0; i < nverts; i++)
|
||||
{
|
||||
|
@ -812,11 +819,35 @@ void SubmitPolygon()
|
|||
ybot = vtx->FinalPosition[1];
|
||||
vbot = i;
|
||||
}
|
||||
|
||||
u32 w = (u32)vtx->Position[3];
|
||||
while ((w >> wshift) & 0xFFFF0000)
|
||||
wshift += 4;
|
||||
}
|
||||
|
||||
poly->VTop = vtop; poly->VBottom = vbot;
|
||||
poly->YTop = ytop; poly->YBottom = ybot;
|
||||
poly->XTop = xtop; poly->XBottom = xbot;
|
||||
poly->WShift = wshift;
|
||||
|
||||
for (int i = 0; i < nverts; i++)
|
||||
{
|
||||
Vertex* vtx = poly->Vertices[i];
|
||||
s32 w = vtx->Position[3] >> wshift;
|
||||
|
||||
s32 z;
|
||||
if (FlushAttributes & 0x2)
|
||||
z = w << wshift;
|
||||
else
|
||||
z = (((s64)vtx->Position[2] * 0x800000) / (w << wshift)) + 0x7FFEFF;
|
||||
|
||||
// checkme
|
||||
if (z < 0) z = 0;
|
||||
else if (z > 0xFFFFFF) z = 0xFFFFFF;
|
||||
|
||||
poly->FinalZ[i] = z;
|
||||
poly->FinalW[i] = w;
|
||||
}
|
||||
|
||||
if (PolygonMode >= 2)
|
||||
LastStripPolygon = poly;
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef struct
|
|||
// final vertex attributes.
|
||||
// allows them to be reused in polygon strips.
|
||||
|
||||
s32 FinalPosition[4];
|
||||
s32 FinalPosition[2];
|
||||
s32 FinalColor[3];
|
||||
|
||||
} Vertex;
|
||||
|
@ -43,6 +43,10 @@ typedef struct
|
|||
Vertex* Vertices[10];
|
||||
u32 NumVertices;
|
||||
|
||||
s32 FinalZ[10];
|
||||
s32 FinalW[10];
|
||||
u8 WShift;
|
||||
|
||||
u32 Attr;
|
||||
u32 TexParam;
|
||||
u32 TexPalette;
|
||||
|
|
|
@ -53,6 +53,243 @@ void Reset()
|
|||
}
|
||||
|
||||
|
||||
// Notes on the interpolator:
|
||||
//
|
||||
// This is a theory on how the DS hardware interpolates values. It matches hardware output
|
||||
// in the tests I did, but the hardware may be doing it differently. You never know.
|
||||
//
|
||||
// Assuming you want to perspective-correctly interpolate a variable named A across two points
|
||||
// in a typical rasterizer, you would calculate A/W and 1/W at each point, interpolate linearly,
|
||||
// then divide A/W by 1/W to recover the correct A value.
|
||||
//
|
||||
// The DS GPU approximates interpolation by calculating a perspective-correct interpolation
|
||||
// between 0 and 1, then using the result as a factor to linearly interpolate the actual
|
||||
// vertex attributes. The factor has 9 bits of precision when interpolating along Y and
|
||||
// 8 bits along X.
|
||||
//
|
||||
// There's a special path for when the two W values are equal: it directly does linear
|
||||
// interpolation, avoiding precision loss from the aforementioned approximation.
|
||||
// Which is desirable when using the GPU to draw 2D graphics.
|
||||
|
||||
class Interpolator
|
||||
{
|
||||
public:
|
||||
Interpolator() {}
|
||||
Interpolator(s32 x0, s32 x1, s32 w0, s32 w1, int shift)
|
||||
{
|
||||
Setup(x0, x1, w0, w1, shift);
|
||||
}
|
||||
|
||||
void Setup(s32 x0, s32 x1, s32 w0, s32 w1, int shift)
|
||||
{
|
||||
this->x0 = x0;
|
||||
this->x1 = x1;
|
||||
this->xdiff = x1 - x0;
|
||||
this->shift = shift;
|
||||
|
||||
this->w0factor = (s64)w0 * xdiff;
|
||||
this->w1factor = (s64)w1 * xdiff;
|
||||
this->wdiff = w1 - w0;
|
||||
}
|
||||
|
||||
void SetX(s32 x)
|
||||
{
|
||||
x -= x0;
|
||||
this->x = x;
|
||||
if (xdiff != 0 && wdiff != 0)
|
||||
{
|
||||
s64 num = ((s64)x << (shift + 40)) / w1factor;
|
||||
s64 denw0 = ((s64)(xdiff-x) << 40) / w0factor;
|
||||
s64 denw1 = num >> shift;
|
||||
|
||||
s64 denom = denw0 + denw1;
|
||||
if (denom == 0)
|
||||
yfactor = 0;
|
||||
else
|
||||
{
|
||||
yfactor = (s32)(num / denom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 Interpolate(s32 y0, s32 y1)
|
||||
{
|
||||
if (xdiff == 0) return y0;
|
||||
|
||||
if (wdiff != 0)
|
||||
return y0 + (((y1 - y0) * yfactor) >> shift);
|
||||
else
|
||||
return y0 + (((y1 - y0) * x) / xdiff);
|
||||
}
|
||||
|
||||
s32 InterpolateZ(s32 y0, s32 y1)
|
||||
{
|
||||
if (xdiff == 0) return y0;
|
||||
|
||||
if (wdiff != 0)
|
||||
return y0 + (((s64)(y1 - y0) * yfactor) >> shift);
|
||||
else
|
||||
return y0 + (((s64)(y1 - y0) * x) / xdiff);
|
||||
}
|
||||
|
||||
private:
|
||||
s32 x0, x1, xdiff, x;
|
||||
s64 w0factor, w1factor;
|
||||
s32 wdiff;
|
||||
int shift;
|
||||
|
||||
s32 yfactor;
|
||||
};
|
||||
|
||||
|
||||
class Slope
|
||||
{
|
||||
public:
|
||||
Slope() {}
|
||||
|
||||
s32 SetupDummy(s32 x0, int side)
|
||||
{
|
||||
if (side)
|
||||
{
|
||||
dx = -0x10000;
|
||||
x0--;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = 0;
|
||||
}
|
||||
|
||||
this->x0 = x0;
|
||||
this->xmin = x0;
|
||||
this->xmax = x0;
|
||||
|
||||
Increment = 0;
|
||||
XMajor = false;
|
||||
|
||||
Interp.Setup(0, 0, 0, 0, 9);
|
||||
Interp.SetX(0);
|
||||
|
||||
return x0;
|
||||
}
|
||||
|
||||
s32 Setup(s32 x0, s32 x1, s32 y0, s32 y1, s32 w0, s32 w1, int side)
|
||||
{
|
||||
this->x0 = x0;
|
||||
this->y = y0;
|
||||
|
||||
if (x1 > x0)
|
||||
{
|
||||
this->xmin = x0;
|
||||
this->xmax = x1-1;
|
||||
}
|
||||
else if (x1 < x0)
|
||||
{
|
||||
this->xmin = x1;
|
||||
this->xmax = x0-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->xmin = x0;
|
||||
if (side) this->xmin--;
|
||||
this->xmax = this->xmin;
|
||||
}
|
||||
|
||||
if (y0 == y1)
|
||||
Increment = 0;
|
||||
else
|
||||
Increment = ((x1 - x0) << 16) / (y1 - y0);
|
||||
|
||||
if (Increment < 0)
|
||||
{
|
||||
Increment = -Increment;
|
||||
Negative = true;
|
||||
}
|
||||
else
|
||||
Negative = false;
|
||||
|
||||
XMajor = (Increment > 0x10000);
|
||||
|
||||
if (side)
|
||||
{
|
||||
// right
|
||||
|
||||
if (XMajor) dx = Negative ? (0x8000 + 0x10000) : (Increment - 0x8000);
|
||||
else if (Increment != 0) dx = Negative ? 0x10000 : 0;
|
||||
else dx = -0x10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
// left
|
||||
|
||||
if (XMajor) dx = Negative ? ((Increment - 0x8000) + 0x10000) : 0x8000;
|
||||
else if (Increment != 0) dx = Negative ? 0x10000 : 0;
|
||||
else dx = 0;
|
||||
}
|
||||
|
||||
if (XMajor)
|
||||
{
|
||||
if (side) Interp.Setup(x0-1, x1-1, w0, w1, 9); // checkme
|
||||
else Interp.Setup(x0, x1, w0, w1, 9);
|
||||
}
|
||||
else Interp.Setup(y0, y1, w0, w1, 9);
|
||||
|
||||
s32 x = XVal();
|
||||
if (XMajor) Interp.SetX(x);
|
||||
else Interp.SetX(y);
|
||||
return x;
|
||||
}
|
||||
|
||||
s32 Step()
|
||||
{
|
||||
dx += Increment;
|
||||
y++;
|
||||
|
||||
s32 x = XVal();
|
||||
if (XMajor) Interp.SetX(x);
|
||||
else Interp.SetX(y);
|
||||
return x;
|
||||
}
|
||||
|
||||
s32 XVal()
|
||||
{
|
||||
s32 ret;
|
||||
if (Negative) ret = x0 - (dx >> 16);
|
||||
else ret = x0 + (dx >> 16);
|
||||
|
||||
if (ret < xmin) ret = xmin;
|
||||
else if (ret > xmax) ret = xmax;
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 EdgeLimit(int side)
|
||||
{
|
||||
s32 ret;
|
||||
if (side)
|
||||
{
|
||||
if (Negative) ret = x0 - ((dx+Increment) >> 16);
|
||||
else ret = x0 + ((dx-Increment) >> 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Negative) ret = x0 - ((dx-Increment) >> 16);
|
||||
else ret = x0 + ((dx+Increment) >> 16);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 Increment;
|
||||
bool Negative;
|
||||
bool XMajor;
|
||||
Interpolator Interp;
|
||||
|
||||
private:
|
||||
s32 x0, xmin, xmax;
|
||||
s32 dx;
|
||||
s32 y;
|
||||
};
|
||||
|
||||
|
||||
void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha)
|
||||
{
|
||||
u32 vramaddr = (texparam & 0xFFFF) << 3;
|
||||
|
@ -65,6 +302,7 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
|
|||
|
||||
// texture wrapping
|
||||
// TODO: optimize this somehow
|
||||
// testing shows that it's hardly worth optimizing, actually
|
||||
|
||||
if (texparam & (1<<16))
|
||||
{
|
||||
|
@ -323,7 +561,7 @@ u32 RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 t)
|
|||
tg = (tcolor >> 4) & 0x3E; if (tg) tg++;
|
||||
tb = (tcolor >> 9) & 0x3E; if (tb) tb++;
|
||||
|
||||
if (blendmode == 1)
|
||||
if (blendmode & 0x1)
|
||||
{
|
||||
// decal
|
||||
|
||||
|
@ -350,7 +588,6 @@ u32 RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 t)
|
|||
else
|
||||
{
|
||||
// modulate
|
||||
// TODO: check that it works the same for shadows
|
||||
|
||||
r = ((tr+1) * (vr+1) - 1) >> 6;
|
||||
g = ((tg+1) * (vg+1) - 1) >> 6;
|
||||
|
@ -409,8 +646,26 @@ void RenderPolygon(Polygon* polygon)
|
|||
int lcur = vtop, rcur = vtop;
|
||||
int lnext, rnext;
|
||||
|
||||
s32 dxl, dxr;
|
||||
s32 lslope, rslope;
|
||||
if (polygon->FacingView)
|
||||
{
|
||||
lnext = lcur + 1;
|
||||
if (lnext >= nverts) lnext = 0;
|
||||
rnext = rcur - 1;
|
||||
if (rnext < 0) rnext = nverts - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lnext = lcur - 1;
|
||||
if (lnext < 0) lnext = nverts - 1;
|
||||
rnext = rcur + 1;
|
||||
if (rnext >= nverts) rnext = 0;
|
||||
}
|
||||
|
||||
|
||||
/*s32 dxl, dxr;
|
||||
s32 lslope, rslope;*/
|
||||
Slope slopeL, slopeR;
|
||||
s32 xL, xR;
|
||||
bool l_xmajor, r_xmajor;
|
||||
|
||||
if (ybot == ytop)
|
||||
|
@ -433,51 +688,52 @@ void RenderPolygon(Polygon* polygon)
|
|||
lcur = vtop; lnext = vtop;
|
||||
rcur = vbot; rnext = vbot;
|
||||
|
||||
lslope = 0; l_xmajor = false;
|
||||
rslope = 0; r_xmajor = false;
|
||||
xL = slopeL.SetupDummy(polygon->Vertices[lcur]->FinalPosition[0], 0);
|
||||
xR = slopeR.SetupDummy(polygon->Vertices[rcur]->FinalPosition[0], 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
//while (polygon->Vertices[lnext]->FinalPosition[1] )
|
||||
if (polygon->FacingView)
|
||||
while (ytop >= polygon->Vertices[lnext]->FinalPosition[1] && lcur != vbot)
|
||||
{
|
||||
lnext = lcur + 1;
|
||||
if (lnext >= nverts) lnext = 0;
|
||||
rnext = rcur - 1;
|
||||
if (rnext < 0) rnext = nverts - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lnext = lcur - 1;
|
||||
if (lnext < 0) lnext = nverts - 1;
|
||||
rnext = rcur + 1;
|
||||
if (rnext >= nverts) rnext = 0;
|
||||
lcur = lnext;
|
||||
|
||||
if (polygon->FacingView)
|
||||
{
|
||||
lnext = lcur + 1;
|
||||
if (lnext >= nverts) lnext = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lnext = lcur - 1;
|
||||
if (lnext < 0) lnext = nverts - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (polygon->Vertices[lnext]->FinalPosition[1] == polygon->Vertices[lcur]->FinalPosition[1])
|
||||
lslope = 0;
|
||||
else
|
||||
lslope = ((polygon->Vertices[lnext]->FinalPosition[0] - polygon->Vertices[lcur]->FinalPosition[0]) << 12) /
|
||||
(polygon->Vertices[lnext]->FinalPosition[1] - polygon->Vertices[lcur]->FinalPosition[1]);
|
||||
xL = slopeL.Setup(polygon->Vertices[lcur]->FinalPosition[0], polygon->Vertices[lnext]->FinalPosition[0],
|
||||
polygon->Vertices[lcur]->FinalPosition[1], polygon->Vertices[lnext]->FinalPosition[1],
|
||||
polygon->FinalW[lcur], polygon->FinalW[lnext], 0);
|
||||
|
||||
if (polygon->Vertices[rnext]->FinalPosition[1] == polygon->Vertices[rcur]->FinalPosition[1])
|
||||
rslope = 0;
|
||||
else
|
||||
rslope = ((polygon->Vertices[rnext]->FinalPosition[0] - polygon->Vertices[rcur]->FinalPosition[0]) << 12) /
|
||||
(polygon->Vertices[rnext]->FinalPosition[1] - polygon->Vertices[rcur]->FinalPosition[1]);
|
||||
while (ytop >= polygon->Vertices[rnext]->FinalPosition[1] && rcur != vbot)
|
||||
{
|
||||
rcur = rnext;
|
||||
|
||||
l_xmajor = (lslope < -0x1000) || (lslope > 0x1000);
|
||||
r_xmajor = (rslope < -0x1000) || (rslope > 0x1000);
|
||||
if (polygon->FacingView)
|
||||
{
|
||||
rnext = rcur - 1;
|
||||
if (rnext < 0) rnext = nverts - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rnext = rcur + 1;
|
||||
if (rnext >= nverts) rnext = 0;
|
||||
}
|
||||
}
|
||||
|
||||
xR = slopeR.Setup(polygon->Vertices[rcur]->FinalPosition[0], polygon->Vertices[rnext]->FinalPosition[0],
|
||||
polygon->Vertices[rcur]->FinalPosition[1], polygon->Vertices[rnext]->FinalPosition[1],
|
||||
polygon->FinalW[rcur], polygon->FinalW[rnext], 1);
|
||||
}
|
||||
|
||||
if (l_xmajor) dxl = (lslope > 0) ? 0x800 : (-lslope-0x800)+0x1000;
|
||||
else if (lslope) dxl = (lslope > 0) ? 0 : 0x1000;
|
||||
else dxl = 0;
|
||||
|
||||
if (r_xmajor) dxr = (rslope > 0) ? rslope-0x800 : 0x800+0x1000;
|
||||
else if (rslope) dxr = (rslope > 0) ? 0 : 0x1000;
|
||||
else dxr = 0x1000;
|
||||
|
||||
if (ybot > 192) ybot = 192;
|
||||
for (s32 y = ytop; y < ybot; y++)
|
||||
{
|
||||
|
@ -501,17 +757,9 @@ void RenderPolygon(Polygon* polygon)
|
|||
}
|
||||
}
|
||||
|
||||
if (polygon->Vertices[lnext]->FinalPosition[1] == polygon->Vertices[lcur]->FinalPosition[1])
|
||||
lslope = 0;
|
||||
else
|
||||
lslope = ((polygon->Vertices[lnext]->FinalPosition[0] - polygon->Vertices[lcur]->FinalPosition[0]) << 12) /
|
||||
(polygon->Vertices[lnext]->FinalPosition[1] - polygon->Vertices[lcur]->FinalPosition[1]);
|
||||
|
||||
l_xmajor = (lslope < -0x1000) || (lslope > 0x1000);
|
||||
|
||||
if (l_xmajor) dxl = (lslope > 0) ? 0x800 : (-lslope-0x800)+0x1000;
|
||||
else if (lslope) dxl = (lslope > 0) ? 0 : 0x1000;
|
||||
else dxl = 0;
|
||||
xL = slopeL.Setup(polygon->Vertices[lcur]->FinalPosition[0], polygon->Vertices[lnext]->FinalPosition[0],
|
||||
polygon->Vertices[lcur]->FinalPosition[1], polygon->Vertices[lnext]->FinalPosition[1],
|
||||
polygon->FinalW[lcur], polygon->FinalW[lnext], 0);
|
||||
}
|
||||
|
||||
if (y >= polygon->Vertices[rnext]->FinalPosition[1] && rcur != vbot)
|
||||
|
@ -532,71 +780,25 @@ void RenderPolygon(Polygon* polygon)
|
|||
}
|
||||
}
|
||||
|
||||
if (polygon->Vertices[rnext]->FinalPosition[1] == polygon->Vertices[rcur]->FinalPosition[1])
|
||||
rslope = 0;
|
||||
else
|
||||
rslope = ((polygon->Vertices[rnext]->FinalPosition[0] - polygon->Vertices[rcur]->FinalPosition[0]) << 12) /
|
||||
(polygon->Vertices[rnext]->FinalPosition[1] - polygon->Vertices[rcur]->FinalPosition[1]);
|
||||
|
||||
r_xmajor = (rslope < -0x1000) || (rslope > 0x1000);
|
||||
|
||||
if (r_xmajor) dxr = (rslope > 0) ? rslope-0x800 : 0x800+0x1000;
|
||||
else if (rslope) dxr = (rslope > 0) ? 0 : 0x1000;
|
||||
else dxr = 0x1000;
|
||||
xR = slopeR.Setup(polygon->Vertices[rcur]->FinalPosition[0], polygon->Vertices[rnext]->FinalPosition[0],
|
||||
polygon->Vertices[rcur]->FinalPosition[1], polygon->Vertices[rnext]->FinalPosition[1],
|
||||
polygon->FinalW[rcur], polygon->FinalW[rnext], 1);
|
||||
}
|
||||
}
|
||||
|
||||
Vertex *vlcur, *vlnext, *vrcur, *vrnext;
|
||||
s32 xstart, xend;
|
||||
s32 xstart_int, xend_int;
|
||||
s32 slope_start, slope_end;
|
||||
Slope* slope_start;
|
||||
Slope* slope_end;
|
||||
|
||||
if (lslope == 0 && rslope == 0 &&
|
||||
polygon->Vertices[lcur]->FinalPosition[0] == polygon->Vertices[rcur]->FinalPosition[0])
|
||||
{
|
||||
xstart = polygon->Vertices[lcur]->FinalPosition[0];
|
||||
xend = xstart;
|
||||
}
|
||||
else
|
||||
{
|
||||
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];
|
||||
xstart = xL;
|
||||
xend = xR;
|
||||
|
||||
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;
|
||||
}
|
||||
s32 wl = slopeL.Interp.Interpolate(polygon->FinalW[lcur], polygon->FinalW[lnext]);
|
||||
s32 wr = slopeR.Interp.Interpolate(polygon->FinalW[rcur], polygon->FinalW[rnext]);
|
||||
|
||||
s32 zl = slopeL.Interp.InterpolateZ(polygon->FinalZ[lcur], polygon->FinalZ[lnext]);
|
||||
s32 zr = slopeR.Interp.InterpolateZ(polygon->FinalZ[rcur], polygon->FinalZ[rnext]);
|
||||
|
||||
// if the left and right edges are swapped, render backwards.
|
||||
// note: we 'forget' to swap the xmajor flags, on purpose
|
||||
|
@ -608,10 +810,13 @@ void RenderPolygon(Polygon* polygon)
|
|||
vrcur = polygon->Vertices[lcur];
|
||||
vrnext = polygon->Vertices[lnext];
|
||||
|
||||
slope_start = rslope;
|
||||
slope_end = lslope;
|
||||
slope_start = &slopeR;
|
||||
slope_end = &slopeL;
|
||||
|
||||
s32 tmp = xstart; xstart = xend; xend = tmp;
|
||||
s32 tmp;
|
||||
tmp = xstart; xstart = xend; xend = tmp;
|
||||
tmp = wl; wl = wr; wr = tmp;
|
||||
tmp = zl; zl = zr; zr = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -620,95 +825,28 @@ void RenderPolygon(Polygon* polygon)
|
|||
vrcur = polygon->Vertices[rcur];
|
||||
vrnext = polygon->Vertices[rnext];
|
||||
|
||||
slope_start = lslope;
|
||||
slope_end = rslope;
|
||||
slope_start = &slopeL;
|
||||
slope_end = &slopeR;
|
||||
}
|
||||
|
||||
// interpolate attributes along Y
|
||||
s64 lfactor1, lfactor2;
|
||||
s64 rfactor1, rfactor2;
|
||||
|
||||
if (l_xmajor)
|
||||
{
|
||||
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];
|
||||
}
|
||||
s32 rl = slope_start->Interp.Interpolate(vlcur->FinalColor[0], vlnext->FinalColor[0]);
|
||||
s32 gl = slope_start->Interp.Interpolate(vlcur->FinalColor[1], vlnext->FinalColor[1]);
|
||||
s32 bl = slope_start->Interp.Interpolate(vlcur->FinalColor[2], vlnext->FinalColor[2]);
|
||||
|
||||
s64 ldenom = lfactor1 + lfactor2;
|
||||
if (ldenom == 0)
|
||||
{
|
||||
lfactor1 = 0x1000;
|
||||
lfactor2 = 0;
|
||||
ldenom = 0x1000;
|
||||
}
|
||||
s32 sl = slope_start->Interp.Interpolate(vlcur->TexCoords[0], vlnext->TexCoords[0]);
|
||||
s32 tl = slope_start->Interp.Interpolate(vlcur->TexCoords[1], vlnext->TexCoords[1]);
|
||||
|
||||
if (r_xmajor)
|
||||
{
|
||||
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];
|
||||
}
|
||||
s32 rr = slope_end->Interp.Interpolate(vrcur->FinalColor[0], vrnext->FinalColor[0]);
|
||||
s32 gr = slope_end->Interp.Interpolate(vrcur->FinalColor[1], vrnext->FinalColor[1]);
|
||||
s32 br = slope_end->Interp.Interpolate(vrcur->FinalColor[2], vrnext->FinalColor[2]);
|
||||
|
||||
s64 rdenom = rfactor1 + rfactor2;
|
||||
if (rdenom == 0)
|
||||
{
|
||||
rfactor1 = 0x1000;
|
||||
rfactor2 = 0;
|
||||
rdenom = 0x1000;
|
||||
}
|
||||
|
||||
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])) / ldenom;
|
||||
s32 wr = ((rfactor1 * vrcur->FinalPosition[3]) + (rfactor2 * vrnext->FinalPosition[3])) / rdenom;
|
||||
|
||||
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])) / ldenom;
|
||||
s32 tl = ((lfactor1 * vlcur->TexCoords[1]) + (lfactor2 * vlnext->TexCoords[1])) / ldenom;
|
||||
|
||||
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])) / rdenom;
|
||||
s32 tr = ((rfactor1 * vrcur->TexCoords[1]) + (rfactor2 * vrnext->TexCoords[1])) / rdenom;
|
||||
s32 sr = slope_end->Interp.Interpolate(vrcur->TexCoords[0], vrnext->TexCoords[0]);
|
||||
s32 tr = slope_end->Interp.Interpolate(vrcur->TexCoords[1], vrnext->TexCoords[1]);
|
||||
|
||||
// calculate edges
|
||||
s32 l_edgeend, r_edgestart;
|
||||
|
||||
if (l_xmajor)
|
||||
{
|
||||
if (slope_start > 0) l_edgeend = vlcur->FinalPosition[0] + ((dxl + slope_start) >> 12);
|
||||
else l_edgeend = vlcur->FinalPosition[0] - ((dxl - slope_start) >> 12);
|
||||
|
||||
if (l_edgeend == xstart) l_edgeend++;
|
||||
}
|
||||
else
|
||||
l_edgeend = xstart + 1;
|
||||
|
||||
if (r_xmajor)
|
||||
{
|
||||
if (slope_end > 0) r_edgestart = vrcur->FinalPosition[0] + ((dxr + slope_end) >> 12);
|
||||
else r_edgestart = vrcur->FinalPosition[0] - ((dxr - slope_end) >> 12);
|
||||
|
||||
if (r_edgestart == xend_int) r_edgestart--;
|
||||
}
|
||||
else
|
||||
r_edgestart = xend - 1;
|
||||
|
||||
//
|
||||
// edge fill rules for opaque pixels:
|
||||
// * right edge is filled if slope > 1
|
||||
// * left edge is filled if slope <= 1
|
||||
|
@ -716,6 +854,39 @@ void RenderPolygon(Polygon* polygon)
|
|||
// edges are always filled if the pixels are translucent
|
||||
// in wireframe mode, there are special rules for equal Z (TODO)
|
||||
|
||||
s32 l_edgeend, r_edgestart;
|
||||
bool l_filledge, r_filledge;
|
||||
|
||||
if (slopeL.XMajor)
|
||||
{
|
||||
l_edgeend = slope_start->EdgeLimit(0);
|
||||
if (l_edgeend == xstart) l_edgeend++;
|
||||
|
||||
l_filledge = slope_start->Negative;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_edgeend = xstart + 1;
|
||||
|
||||
l_filledge = true;
|
||||
}
|
||||
|
||||
if (slopeR.XMajor)
|
||||
{
|
||||
r_edgestart = slope_end->EdgeLimit(1);
|
||||
if (r_edgestart == xend) r_edgestart--;
|
||||
|
||||
r_filledge = !slope_end->Negative;
|
||||
}
|
||||
else
|
||||
{
|
||||
r_edgestart = xend - 1;
|
||||
|
||||
r_filledge = slope_end->Increment==0;
|
||||
}
|
||||
|
||||
Interpolator interpX(xstart, xend+1, wl, wr, 8);
|
||||
|
||||
for (s32 x = xstart; x <= xend; x++)
|
||||
{
|
||||
if (x < 0) continue;
|
||||
|
@ -731,28 +902,20 @@ void RenderPolygon(Polygon* polygon)
|
|||
if (wireframe && edge==0)
|
||||
continue;
|
||||
|
||||
s64 factor1 = (xend+1 - x) * wr;
|
||||
s64 factor2 = (x - xstart) * wl;
|
||||
s64 denom = factor1 + factor2;
|
||||
if (denom == 0)
|
||||
{
|
||||
factor1 = 0x1000;
|
||||
factor2 = 0;
|
||||
denom = 0x1000;
|
||||
}
|
||||
interpX.SetX(x);
|
||||
|
||||
u32 pixeladdr = (y*256) + x;
|
||||
|
||||
s32 z = ((factor1 * zl) + (factor2 * zr)) / denom;
|
||||
s32 z = interpX.InterpolateZ(zl, zr);
|
||||
if (!fnDepthTest(DepthBuffer[pixeladdr], z))
|
||||
continue;
|
||||
|
||||
u32 vr = ((factor1 * rl) + (factor2 * rr)) / denom;
|
||||
u32 vg = ((factor1 * gl) + (factor2 * gr)) / denom;
|
||||
u32 vb = ((factor1 * bl) + (factor2 * br)) / denom;
|
||||
u32 vr = interpX.Interpolate(rl, rr);
|
||||
u32 vg = interpX.Interpolate(gl, gr);
|
||||
u32 vb = interpX.Interpolate(bl, br);
|
||||
|
||||
s16 s = ((factor1 * sl) + (factor2 * sr)) / denom;
|
||||
s16 t = ((factor1 * tl) + (factor2 * tr)) / denom;
|
||||
s16 s = interpX.Interpolate(sl, sr);
|
||||
s16 t = interpX.Interpolate(tl, tr);
|
||||
|
||||
u32 color = RenderPixel(polygon, vr>>3, vg>>3, vb>>3, s, t);
|
||||
u32 attr = 0;
|
||||
|
@ -781,11 +944,11 @@ void RenderPolygon(Polygon* polygon)
|
|||
{
|
||||
// edge fill rules for opaque pixels
|
||||
// TODO, eventually: antialiasing
|
||||
if (!wireframe)// && !(edge & 0x4))
|
||||
if (!wireframe)
|
||||
{
|
||||
if ((edge & 0x1) && slope_start > 0x1000)
|
||||
if ((edge & 0x1) && !l_filledge)
|
||||
continue;
|
||||
if ((edge & 0x2) && (slope_end != 0 && slope_end <= 0x1000))
|
||||
if ((edge & 0x2) && !r_filledge)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -824,19 +987,9 @@ void RenderPolygon(Polygon* polygon)
|
|||
AttrBuffer[pixeladdr] = attr;
|
||||
}
|
||||
|
||||
if (lslope > 0) dxl += lslope;
|
||||
else dxl -= lslope;
|
||||
if (rslope > 0) dxr += rslope;
|
||||
else dxr -= rslope;
|
||||
xL = slopeL.Step();
|
||||
xR = slopeR.Step();
|
||||
}
|
||||
|
||||
/*for (int i = 0; i < polygon->NumVertices; i++)
|
||||
{
|
||||
Vertex* vtx = polygon->Vertices[i];
|
||||
u32 addr = vtx->FinalPosition[0] + (vtx->FinalPosition[1]*256);
|
||||
if (addr < 256*192)
|
||||
ColorBuffer[addr] = 0x1F3F003F;
|
||||
}*/
|
||||
}
|
||||
|
||||
void RenderFrame(Vertex* vertices, Polygon* polygons, int npolys)
|
||||
|
@ -863,7 +1016,6 @@ void RenderFrame(Vertex* vertices, Polygon* polygons, int npolys)
|
|||
u32 color = r | (g << 8) | (b << 16) | a;
|
||||
|
||||
u32 z = ((val3 & 0x7FFF) * 0x200) + 0x1FF;
|
||||
if (z >= 0x10000 && z < 0xFFFFFF) z++;
|
||||
|
||||
ColorBuffer[y+x] = color;
|
||||
DepthBuffer[y+x] = z;
|
||||
|
@ -885,7 +1037,6 @@ void RenderFrame(Vertex* vertices, Polygon* polygons, int npolys)
|
|||
u32 color = r | (g << 8) | (b << 16) | (a << 24);
|
||||
|
||||
u32 z = ((RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF;
|
||||
if (z >= 0x10000 && z < 0xFFFFFF) z++;
|
||||
|
||||
polyid |= ((RenderClearAttr1 & 0x8000) >> 7);
|
||||
|
||||
|
|
Loading…
Reference in New Issue