Micro Sub Pixel Rendering (mspxr) Copyright (C) 2024 Canmi, all rights reserved.
Introduction
mspxr is a lightweight graphic rendering library. It leverages the unique properties of LCDs to display 3x times more pixels using limited physical pixels. Additionally, it employs anti-aliasing techniques to enhance the detail and smoothness of fonts and images.
Dot
Here is a 1px dot.
Line
Rectangle
We can use these dots to construct a rectangle.
Circle?
Without anti-aliasing, it may seem like your screen resolution is too low. But do you really need such a high resolution?
Midpoint Circle Algorithm
The Midpoint Circle Algorithm is an efficient method for drawing a circle on a grid by using symmetry and a decision-making process to determine the next pixel to plot based on a midpoint criterion.
// Use Bresenham's algorithm to draw the circle while (y >= x) { // Plot points in all octants mspxr_draw_dot(center_x + x, center_y + y, color); mspxr_draw_dot(center_x - x, center_y + y, color); mspxr_draw_dot(center_x + x, center_y - y, color); mspxr_draw_dot(center_x - x, center_y - y, color); mspxr_draw_dot(center_x + y, center_y + x, color); mspxr_draw_dot(center_x - y, center_y + x, color); mspxr_draw_dot(center_x + y, center_y - x, color); mspxr_draw_dot(center_x - y, center_y - x, color);
Now we have a circle, but it’s not exactly what we want.
Rounded Rectangle
We can divide this circle into four pieces to create a corner for a rounded rectangle.
Now we can use a circle divided into 4 corners and 5 rectangles to form a rounded rectangle.
Rounded Rectangle:
To draw a rounded rectangle, the algorithm combines straight lines for the rectangle’s edges and circular arcs for its corners. The edges of the rectangle are drawn using straight lines:
Draw horizontal lines from , maintaining the y-coordinates at and , and draw vertical lines from to , maintaining the x-coordinates at and .
Top Section: For lines where the current y-coordinate is within the top rounded corner area, the x-coordinates are calculated based on the circle equation:
Horizontal lines are drawn between:
Middle Section: For lines in the middle rectangle (outside the corner areas), the horizontal lines span directly between:
Bottom Section: For lines in the bottom rounded corner area, the x-coordinates are calculated similarly to the top section, but using the offset from the bottom:
voidmspxr_draw_rounded_rectangle_filled(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t corner, uint16_t color) { for (uint16_t y = y1; y <= y2; y++) { if (y < y1 + corner) { int16_t dy = y1 + corner - y; int16_t dx = (int16_t)(sqrt(corner * corner - dy * dy)); mspxr_draw_straight_line(x1 + corner - dx, y, x2 - corner + dx, y, color); } elseif (y > y2 - corner) { int16_t dy = y - (y2 - corner); int16_t dx = (int16_t)(sqrt(corner * corner - dy * dy)); mspxr_draw_straight_line(x1 + corner - dx, y, x2 - corner + dx, y, color); } else { mspxr_draw_straight_line(x1, y, x2, y, color); } } }
FXAA
FXAA (Fast Approximate Anti-Aliasing) is a modern technique developed to reduce the jagged edges (aliasing) that appear in graphics, especially on diagonal or curved lines. Unlike traditional anti-aliasing methods, FXAA operates as a post-processing effect, smoothing out edges without the need for heavy computational power. It works by blending the colors of pixels along the edges, which reduces the visual impact of jaggedness. FXAA is widely used in real-time rendering applications, offering a balance between quality and performance.
Blend Color
In order to use FXAA, we must create some extra pixels for transitioning.
Blended Color =
Where:
is the foreground color (the pixel being drawn).
is the background color (the pixel already in place).
is the alpha value (ranging from 0 to 255), which controls the mix between the two colors.
This formula ensures a smooth gradient by proportionally mixing the two colors based on the alpha value, where higher alpha emphasizes the foreground color.
// Combine into 16-bit color (RGB565 format) return (r << 11) | (g << 5) | b; }
FXAA Circle
We can renders a filled circle with a smooth, anti-aliased edge using Fast Approximate Anti-Aliasing (FXAA). The function draws the solid interior of the circle first and then gradually blends the outer edge into the background, creating a smooth transition.
Circle Interior:
Iterate through all pixels within the radius of the circle, drawing them with the specified foreground color. For a pixel at coordinates relative to the circle’s center, it is part of the interior if:
Anti-Aliased Edge:
Pixels in the transition zone are determined based on their distance from the circle’s edge. The transition zone spans from to , where “expansion” controls the width of the blending area.
In embedded applications with limited resources, optimizing for bufferless scenarios is essential. Therefore, rather than using four full circles to create a rounded rectangle, we generate four quarter-circle segments.
A quarter-circle is restricted to the first quadrant, expanding to the right and downward from the center point. The pixel coordinates
must satisfy:
To check if a pixel (𝑑𝑥, 𝑑𝑦) falls within the extended circular area, compute its Euclidean distance from the circle’s center:
A pixel is part of the extended circle if:
Drawing Logic: For pixels inside the original circle:
Draw with the solid foreground color.
For pixels within the transition (anti-aliased) zone:
Compute the alpha value for blending based on the distance:
Use this alpha value to blend the foreground and background colors for smooth edges.
FXAA Rounded Rectangle
Building on the previous method for drawing a quarter-circle, we can break down a rounded rectangle with anti-aliasing into four quarter-circles for the corners and three rectangles to complete the shape.
Building on the approach described above, we can add support for subpixel rendering by performing triple sampling of horizontal pixels, calculating weights, and compressing the subpixels back into place. While the specifics of the subpixel algorithm are not detailed here, the image below illustrates a comparison between a rounded rectangle calculated with subpixel and anti-aliasing techniques and a simple rounded rectangle.