stb_truetype: fix incorrect antialiasing computation in v2 rasterizer, and handle certain cases where math blew up

This commit is contained in:
Sean Barrett
2021-07-11 16:26:02 -07:00
parent e05ecc05ee
commit 0be82e4814
3 changed files with 52 additions and 16 deletions

View File

@ -3120,7 +3120,7 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
} else {
int x,x1,x2;
float y_crossing, step, sign, area;
float y_crossing, y_final, step, sign, area;
// covers 2+ pixels
if (x_top > x_bottom) {
// flip scanline vertically; signed area is the same
@ -3133,28 +3133,39 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
dy = -dy;
t = x0, x0 = xb, xb = t;
}
assert(dy >= 0);
assert(dx >= 0);
x1 = (int) x_top;
x2 = (int) x_bottom;
// compute intersection with y axis at x1+1
y_crossing = (x1+1 - x0) * dy + y_top;
// if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
if (y_crossing > y_bottom)
y_crossing = y_bottom;
sign = e->direction;
// area of the rectangle covered from y0..y_crossing
area = sign * (y_crossing-sy0);
// area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
scanline[x1] += area * (x1+1 - x_top)/2;
step = sign * dy;
// check if final y_crossing is blown up; no test case for this
y_final = y_crossing + dy * (x2 - (x1+1)); // advance y by number of steps taken below
if (y_final > y_bottom) {
y_final = y_bottom;
dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
}
step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, which is also how much pixel area changes for each step in x
for (x = x1+1; x < x2; ++x) {
scanline[x] += area + step/2;
scanline[x] += area + step/2; // area of parallelogram is step/2
area += step;
}
y_crossing += dy * (x2 - (x1+1));
STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
STBTT_assert(STBTT_fabs(area) <= 1.01f);
scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
// area of the triangle (x2,y_crossing), (x_bottom,y1), (x2,y1)
scanline[x2] += area + sign * (x_bottom - x2)/2 * (sy1-y_crossing);
scanline_fill[x2] += sign * (sy1-sy0);
}