Search guides and the APICtrl K
  1. API reference
  2. Native GUI

gfx/bitmap.h

Bitmap: premultiplied RGBA8, and the antialiased rasteriser that fills it.

#include <sonore/gfx/bitmap.h>
On this page

Design notes

Why this SDK rasterises rather than calling the platform

A framework draws through Direct2D, CoreGraphics and Cairo. This draws into a buffer and lets each platform blit it. The reason is testability.

A generated interface cannot be checked by looking at it -- "attractive" is not assertable, and nobody here can see a Mac at all. But a rasteriser that writes into memory CAN be checked: fill a rectangle and count the pixels, fill a circle and compare opposite sides, fill something off-screen and prove the buffer did not change. Those tests run anywhere, in a second, with no window.

It also means one renderer instead of three, so there is no bug that only appears on the platform nobody can build for.

The antialiasing, and why 16 sub-rows

Coverage is measured by sampling each pixel row at 16 evenly spaced heights and, within each, computing EXACT horizontal coverage of the spans. So the horizontal direction is continuous and the vertical is quantised to sixteenths.

That asymmetry is deliberate and cheap: a near-horizontal edge -- the top of a slider track, the shoulder of a meter -- is where banding would be visible, and it is horizontal coverage that resolves it. Sixteen levels vertically is finer than an 8-bit channel can show on a near-vertical edge.

Types 3

A premultiplied RGBA8 image, row-major, tightly packed.

A bitmap repeated across the plane, in DEVICE space.

A panel texture, a brushed-metal background, a grid. The alternative is drawing the same small image in a double loop, which works and costs a separate blit per tile plus the arithmetic to stop at the edges -- and gets the edges wrong the first time somebody clips it to a rounded rectangle.

NEAREST sampling, deliberately. A texture tiled at its natural size wants to stay crisp, and bilinear at 1:1 blurs every pixel with its neighbours for no benefit at all. A scaled tile is the unusual case and takes the same treatment rather than a second code path with a different look.

Fills paths into a Bitmap.

Holds its scratch buffers between calls: a UI redraw fills hundreds of paths, and allocating an edge list per fill would put the allocator on the repaint path. Which also makes one Rasteriser single-threaded state: each Graphics owns its own, and two threads filling at once need two. The antialiasing it does is described in the file comment.

↑↓ to move↵ to openEvery public name in the headers, and every guide