Pica/Rasterizer: Make orient2d a free function and rename it to SignedArea.

This commit is contained in:
Tony Wasserka 2014-12-31 15:19:40 +01:00
parent 47543d62cf
commit 9675d19b47
1 changed files with 39 additions and 32 deletions

View File

@ -55,12 +55,8 @@ static void SetDepth(int x, int y, u16 value) {
*(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value; *(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value;
} }
void ProcessTriangle(const VertexShader::OutputVertex& v0, // NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
const VertexShader::OutputVertex& v1, struct Fix12P4 {
const VertexShader::OutputVertex& v2)
{
// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
struct Fix12P4 {
Fix12P4() {} Fix12P4() {}
Fix12P4(u16 val) : val(val) {} Fix12P4(u16 val) : val(val) {}
@ -75,24 +71,35 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
return (u16)*this < (u16)oth; return (u16)*this < (u16)oth;
} }
private: private:
u16 val; u16 val;
}; };
// vertex positions in rasterizer coordinates /**
auto FloatToFix = [](float24 flt) { * Calculate signed area of the triangle spanned by the three argument vertices.
return Fix12P4(static_cast<unsigned short>(flt.ToFloat32() * 16.0f)); * The sign denotes an orientation.
}; *
auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) { * @todo define orientation concretely.
return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; */
}; static int SignedArea (const Math::Vec2<Fix12P4>& vtx1,
static auto orient2d = [](const Math::Vec2<Fix12P4>& vtx1,
const Math::Vec2<Fix12P4>& vtx2, const Math::Vec2<Fix12P4>& vtx2,
const Math::Vec2<Fix12P4>& vtx3) { const Math::Vec2<Fix12P4>& vtx3) {
const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0); const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0);
const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0); const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0);
// TODO: There is a very small chance this will overflow for sizeof(int) == 4 // TODO: There is a very small chance this will overflow for sizeof(int) == 4
return Math::Cross(vec1, vec2).z; return Math::Cross(vec1, vec2).z;
};
void ProcessTriangle(const VertexShader::OutputVertex& v0,
const VertexShader::OutputVertex& v1,
const VertexShader::OutputVertex& v2)
{
// vertex positions in rasterizer coordinates
auto FloatToFix = [](float24 flt) {
return Fix12P4(static_cast<unsigned short>(flt.ToFloat32() * 16.0f));
};
auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) {
return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
}; };
Math::Vec3<Fix12P4> vtxpos[3]{ ScreenToRasterizerCoordinates(v0.screenpos), Math::Vec3<Fix12P4> vtxpos[3]{ ScreenToRasterizerCoordinates(v0.screenpos),
@ -107,7 +114,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
if (registers.cull_mode != Regs::CullMode::KeepAll) { if (registers.cull_mode != Regs::CullMode::KeepAll) {
// Cull away triangles which are wound clockwise. // Cull away triangles which are wound clockwise.
// TODO: A check for degenerate triangles ("== 0") should be considered for CullMode::KeepAll // TODO: A check for degenerate triangles ("== 0") should be considered for CullMode::KeepAll
if (orient2d(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) if (SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0)
return; return;
} }
@ -153,9 +160,9 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
for (u16 x = min_x; x < max_x; x += 0x10) { for (u16 x = min_x; x < max_x; x += 0x10) {
// Calculate the barycentric coordinates w0, w1 and w2 // Calculate the barycentric coordinates w0, w1 and w2
int w0 = bias0 + orient2d(vtxpos[1].xy(), vtxpos[2].xy(), {x, y}); int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y});
int w1 = bias1 + orient2d(vtxpos[2].xy(), vtxpos[0].xy(), {x, y}); int w1 = bias1 + SignedArea(vtxpos[2].xy(), vtxpos[0].xy(), {x, y});
int w2 = bias2 + orient2d(vtxpos[0].xy(), vtxpos[1].xy(), {x, y}); int w2 = bias2 + SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), {x, y});
int wsum = w0 + w1 + w2; int wsum = w0 + w1 + w2;
// If current pixel is not covered by the current primitive // If current pixel is not covered by the current primitive