Add anti-aliased font rendering with dithering

Replace solid black rendering of anti-aliased font edges with period-2 dithering patterns. Full coverage pixels render as solid ink, while partial coverage pixels use checkerboard patterns (50% for dark grey, 25% for light grey) matching fillRectDither behavior. This prevents edge pixels from bolding to black on BW displays and produces proper anti-aliasing for 2-bit fonts.
This commit is contained in:
Justin Mitchell
2026-07-05 16:06:56 -04:00
parent 3e1dd31e53
commit 62448b3c08
9 changed files with 17947 additions and 11245 deletions
+9 -2
View File
@@ -282,8 +282,15 @@ static void renderCharImpl(const GfxRenderer& renderer, GfxRenderer::RenderMode
const uint8_t bmpVal = 3 - ((byte >> bit_index) & 0x3);
if (renderMode == GfxRenderer::BW && bmpVal < 3) {
// Black (also paints over the grays in BW mode)
renderer.drawPixel(screenX, screenY, pixelState);
// Full coverage is solid ink; partial (anti-aliased edge) coverage
// dithers with the same period-2 patterns as fillRectDither
// (dark grey = 50% checkerboard, light grey = 25%), so 2-bit fonts
// render anti-aliased on BW passes instead of bolding every edge
// pixel to black. Skipped pixels leave the background untouched.
if (bmpVal == 0 || (bmpVal == 1 && ((screenX + screenY) & 1) == 0) ||
(bmpVal == 2 && (screenX & 1) == 0 && (screenY & 1) == 0)) {
renderer.drawPixel(screenX, screenY, pixelState);
}
} else if (renderMode == GfxRenderer::GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
// Light gray (also mark the MSB if it's going to be a dark gray too)
// Dedicated X3 gray LUTs now provide proper 4-level gray on both devices