Skip to content

Commit

Permalink
render: added fill rule for polygon rasterization
Browse files Browse the repository at this point in the history
  • Loading branch information
JaCzekanski committed Aug 25, 2019
1 parent bac444d commit 55621f3
Showing 1 changed file with 38 additions and 27 deletions.
65 changes: 38 additions & 27 deletions src/device/gpu/render/render_polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ INLINE void plotPixel(GPU* gpu, const ivec2 p, const ivec3 s, const int area, co
VRAM[p.y][p.x] = c.raw;
}

static bool isTopLeft(const ivec2 e) { return e.y < 0 || (e.y == 0 && e.x < 0); }

template <ColorDepth bits>
INLINE void triangle(GPU* gpu, const ivec2 pos[3], const ivec3 color[3], const ivec2 tex[3], const ivec2 texPage, const ivec2 clut,
const int flags, const gpu::GP0_E2 textureWindow, const gpu::GP0_E6 maskSettings) {
Expand All @@ -141,37 +143,45 @@ INLINE void triangle(GPU* gpu, const ivec2 pos[3], const ivec3 color[3], const i
);

// https://fgiesen.wordpress.com/2013/02/10/optimizing-the-basic-rasterizer/
const int A01 = pos[0].y - pos[1].y;
const int B01 = pos[1].x - pos[0].x;

const int A12 = pos[1].y - pos[2].y;
const int B12 = pos[2].x - pos[1].x;

const int A20 = pos[2].y - pos[0].y;
const int B20 = pos[0].x - pos[2].x;

const ivec2 minp = ivec2(min.x, min.y);

int w0_row = orient2d(pos[1], pos[2], minp);
int w1_row = orient2d(pos[2], pos[0], minp);
int w2_row = orient2d(pos[0], pos[1], minp);
// Delta constants
const ivec2 D01(pos[1].x - pos[0].x, pos[0].y - pos[1].y);
const ivec2 D12(pos[2].x - pos[1].x, pos[1].y - pos[2].y);
const ivec2 D20(pos[0].x - pos[2].x, pos[2].y - pos[0].y);

// Fill rule
const int bias[3] = {
isTopLeft(D12) ? -1 : 0, //
isTopLeft(D20) ? -1 : 0, //
isTopLeft(D01) ? -1 : 0 //
};

// Calculate half-space values for first pixel
int CY[3] = {
orient2d(pos[1], pos[2], min) + bias[0], //
orient2d(pos[2], pos[0], min) + bias[1], //
orient2d(pos[0], pos[1], min) + bias[2] //
};

ivec2 p;

for (p.y = min.y; p.y < max.y; p.y++) {
ivec3 is = ivec3(w0_row, w1_row, w2_row);
ivec3 CX = ivec3(CY[0], CY[1], CY[2]);

for (p.x = min.x; p.x < max.x; p.x++) {
if ((is.x | is.y | is.z) >= 0) {
plotPixel<bits>(gpu, p, is, area, color, tex, texPage, clut, flags, textureWindow, maskSettings);
if ((CX[0] | CX[1] | CX[2]) > 0) {
// Bias is subtracted to remove error from texture sampling.
// I don't like this, but haven't found other solution that would fix this issue.
ivec3 s(CX[0] - bias[0], CX[1] - bias[1], CX[2] - bias[2]);
plotPixel<bits>(gpu, p, s, area, color, tex, texPage, clut, flags, textureWindow, maskSettings);
}

is.x += A12;
is.y += A20;
is.z += A01;
CX[0] += D12.y;
CX[1] += D20.y;
CX[2] += D01.y;
}
w0_row += B12;
w1_row += B20;
w2_row += B01;
CY[0] += D12.x;
CY[1] += D20.x;
CY[2] += D01.x;
}
}

Expand Down Expand Up @@ -211,12 +221,13 @@ void Render::drawTriangle(GPU* gpu, Vertex v[3]) {
if (abs(pos[j].y - pos[(j + 1) % 3].y) >= 512) return;
}

if (bits == 0)
if (bits == 0) {
triangle<ColorDepth::NONE>(gpu, pos, color, texcoord, texpage, clut, flags, textureWindow, maskSettings);
else if (bits == 4)
} else if (bits == 4) {
triangle<ColorDepth::BIT_4>(gpu, pos, color, texcoord, texpage, clut, flags, textureWindow, maskSettings);
else if (bits == 8)
} else if (bits == 8) {
triangle<ColorDepth::BIT_8>(gpu, pos, color, texcoord, texpage, clut, flags, textureWindow, maskSettings);
else if (bits == 16)
} else if (bits == 16) {
triangle<ColorDepth::BIT_16>(gpu, pos, color, texcoord, texpage, clut, flags, textureWindow, maskSettings);
}
}

0 comments on commit 55621f3

Please sign in to comment.