71concept pixel_surface =
requires(S& s,
const S& cs,
size_t x,
size_t y,
typename S::pixel_type pixel) {
72 typename S::pixel_type;
73 { s.set_pixel(x, y, pixel) }
noexcept;
74 { cs.width() } -> std::convertible_to<size_t>;
75 { cs.height() } -> std::convertible_to<size_t>;
93template<pixel_surface Surface>
100 typename Surface::pixel_type ink
102 const size_t surface_width = surface.width();
103 const size_t surface_height = surface.height();
104 if (x >= surface_width || y >= surface_height) {
107 const size_t x_end = x + std::min(width, surface_width - x);
108 const size_t y_end = y + std::min(height, surface_height - y);
109 for (
size_t py = y; py < y_end; ++py) {
110 for (
size_t px = x; px < x_end; ++px) {
111 surface.set_pixel(px, py, ink);
129template<pixel_surface Surface>
130void draw_hline(Surface& surface,
size_t x,
size_t y,
size_t length,
typename Surface::pixel_type ink)
noexcept {
131 fill_rect(surface, x, y, length, 1, ink);
147template<pixel_surface Surface>
148void draw_vline(Surface& surface,
size_t x,
size_t y,
size_t length,
typename Surface::pixel_type ink)
noexcept {
149 fill_rect(surface, x, y, 1, length, ink);
167template<pixel_surface Surface>
174 typename Surface::pixel_type ink
176 if (width == 0 || height == 0) {
179 if (width <= 2 || height <= 2) {
180 fill_rect(surface, x, y, width, height, ink);
184 draw_hline(surface, x, y + height - 1, width, ink);
185 draw_vline(surface, x, y + 1, height - 2, ink);
186 draw_vline(surface, x + width - 1, y + 1, height - 2, ink);
203template<pixel_surface Surface>
210 typename Surface::pixel_type ink
212 if (std::min(x0, x1) >= surface.width() || std::min(y0, y1) >= surface.height()) {
217 ptrdiff_t px =
static_cast<ptrdiff_t
>(x0);
218 ptrdiff_t py =
static_cast<ptrdiff_t
>(y0);
219 const ptrdiff_t ex =
static_cast<ptrdiff_t
>(x1);
220 const ptrdiff_t ey =
static_cast<ptrdiff_t
>(y1);
221 const ptrdiff_t dx = std::abs(ex - px);
222 const ptrdiff_t dy = -std::abs(ey - py);
223 const ptrdiff_t sx = px < ex ? 1 : -1;
224 const ptrdiff_t sy = py < ey ? 1 : -1;
225 ptrdiff_t err = dx + dy;
227 surface.set_pixel(
static_cast<size_t>(px),
static_cast<size_t>(py), ink);
228 if (px == ex && py == ey) {
231 const ptrdiff_t e2 = 2 * err;
264template<pixel_surface Surface>
270 std::string_view text,
271 typename Surface::pixel_type ink,
277 if (y >= surface.height()) {
283 for (
char c : text) {
284 if (cell_x >= surface.width()) {
288 const uint8_t* glyph = font.
glyph(c);
289 for (
size_t row = 0; row < font.
height; ++row) {
290 const uint8_t* row_bits = glyph + row * bpr;
292 for (
size_t col = 0; col < font.
width; ++col, bits <<= 1) {
294 bits = row_bits[col / 8];
296 if (!(bits & 0x80u)) {
299 const size_t px = cell_x + col * scale;
300 const size_t py = y + row * scale;
301 for (
unsigned sy = 0; sy < scale; ++sy) {
302 for (
unsigned sx = 0; sx < scale; ++sx) {
303 surface.set_pixel(px + sx, py + sy, ink);
309 cell_x += font.
advance(c) * scale;
327template<pixel_surface Surface>
328 requires std::same_as<typename Surface::pixel_type, bool>
330 draw_text(surface, font, x, y, text,
true);
392template<pixel_surface Surface>
431 , _dx(
static_cast<ptrdiff_t
>(x))
432 , _dy(
static_cast<ptrdiff_t
>(y))
434 , _height(y +
surface.height()) {}
437 [[nodiscard]] Surface&
surface() const noexcept {
return *_surface; }
447 [[nodiscard]]
size_t width() const noexcept {
return _width; }
457 [[nodiscard]]
size_t height() const noexcept {
return _height; }
483 sub._dx = _dx -
static_cast<ptrdiff_t
>(x);
484 sub._dy = _dy -
static_cast<ptrdiff_t
>(y);
485 sub._width = x < _width ? std::min(
width, _width - x) : 0;
486 sub._height = y < _height ? std::min(
height, _height - y) : 0;
501 if (x >= _width || y >= _height) {
507 static_cast<size_t>(
static_cast<ptrdiff_t
>(x) - _dx),
508 static_cast<size_t>(
static_cast<ptrdiff_t
>(y) - _dy),
524 if constexpr (
requires(Surface& s,
pixel_type i) {
525 { s.fill(i) }
noexcept;
527 if (_covers_surface()) {
546 if constexpr (
requires(Surface& s) {
547 { s.clear() }
noexcept;
549 if (_covers_surface()) {
573 template<
typename... Args>
574 requires requires(Surface& s) { s.flush(std::declval<Args>()...); }
575 decltype(
auto)
flush(Args&&... args)
const {
576 return _surface->flush(std::forward<Args>(args)...);
593 template<
typename... Args>
594 requires requires(Surface& s) { s.try_flush(std::declval<Args>()...); }
595 [[nodiscard]]
decltype(
auto)
try_flush(Args&&... args)
const {
596 return _surface->try_flush(std::forward<Args>(args)...);
616 const size_t sx = std::max(x, _dx > 0 ?
static_cast<size_t>(_dx) :
size_t{0});
617 const size_t sy = std::max(y, _dy > 0 ?
static_cast<size_t>(_dy) :
size_t{0});
618 if (sx >= _width || sy >= _height || sx - x >=
width || sy - y >=
height) {
623 static_cast<size_t>(
static_cast<ptrdiff_t
>(sx) - _dx),
624 static_cast<size_t>(
static_cast<ptrdiff_t
>(sy) - _dy),
625 std::min(
width - (sx - x), _width - sx),
626 std::min(
height - (sy - y), _height - sy),
713 std::string_view text,
732 requires std::same_as<pixel_type, bool>
740 [[nodiscard]]
bool _covers_surface() const noexcept {
741 return _dx >= 0 && _dy >= 0 &&
static_cast<size_t>(_dx) + _surface->width() <= _width &&
742 static_cast<size_t>(_dy) + _surface->height() <= _height;
758template<
typename Surface,
typename Dest,
typename DrawFn>
759concept banded_renderable = pixel_surface<Surface> &&
requires(canvas<Surface>& c, Dest& dest, DrawFn& draw) {
761 { c.try_flush(dest,
size_t{},
size_t{}) } -> std::same_as<result<void>>;
766template<pixel_surface Surface,
typename Dest,
typename DrawFn>
767 requires banded_renderable<Surface, Dest, DrawFn>
768[[nodiscard]] result<void>
try_render_banded(Surface& band, Dest& dest,
size_t frame_height, DrawFn&& draw);
771#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
809template<pixel_surface Surface,
typename Dest,
typename DrawFn>
810 requires banded_renderable<Surface, Dest, DrawFn>
811void render_banded(Surface& band, Dest& dest,
size_t frame_height, DrawFn&& draw) {
845template<pixel_surface Surface,
typename Dest,
typename DrawFn>
846 requires banded_renderable<Surface, Dest, DrawFn>
848 const size_t band_height = band.height();
849 if (band_height == 0 || frame_height == 0 || frame_height % band_height != 0) {
852 for (
size_t y = 0; y < frame_height; y += band_height) {
856 if (
auto flushed = c.
try_flush(dest,
size_t{0}, y); !flushed) {
A drawing view bundling a pixel surface with the drawing primitives.
canvas(Surface &surface) noexcept
Creates a canvas drawing on the given surface.
void draw_text(const font::mono_font &font, size_t x, size_t y, std::string_view text, pixel_type ink, unsigned scale=1) noexcept
Draws text with the given ink.
size_t height() const noexcept
Returns the height of the canvas's coordinate space, in pixels.
decltype(auto) flush(Args &&... args) const
Pushes the surface's content onward, on surfaces that support it.
canvas window(size_t x, size_t y, size_t width, size_t height) const noexcept
Returns a canvas for a sub-region of this one.
void clear() noexcept
Sets every drawable pixel to the default value (equivalent to fill(pixel_type{})).
void fill(pixel_type ink) noexcept
Sets every drawable pixel to the given ink.
void draw_hline(size_t x, size_t y, size_t length, pixel_type ink) noexcept
Draws a horizontal line with the given ink.
void draw_line(size_t x0, size_t y0, size_t x1, size_t y1, pixel_type ink) noexcept
Draws a straight line between two points with the given ink.
canvas(Surface &surface, size_t x, size_t y) noexcept
Creates a canvas whose surface sits at (x, y) in the canvas's coordinates.
void draw_rect(size_t x, size_t y, size_t width, size_t height, pixel_type ink) noexcept
Outlines a rectangle with the given ink.
typename Surface::pixel_type pixel_type
The pixel value type of the underlying surface.
size_t width() const noexcept
Returns the width of the canvas's coordinate space, in pixels.
void draw_text(const font::mono_font &font, size_t x, size_t y, std::string_view text) noexcept
Draws text on a monochrome surface, setting glyph ink pixels.
void fill_rect(size_t x, size_t y, size_t width, size_t height, pixel_type ink) noexcept
Fills a rectangle with the given ink.
void set_pixel(size_t x, size_t y, pixel_type ink) noexcept
Sets a single pixel to the given ink.
Surface & surface() const noexcept
Returns the underlying surface.
decltype(auto) try_flush(Args &&... args) const
Pushes the surface's content onward, on surfaces that support it.
void draw_vline(size_t x, size_t y, size_t length, pixel_type ink) noexcept
Draws a vertical line with the given ink.
A drawable two-dimensional pixel surface.
Bitmap font representation and text metrics.
result< void > try_render_banded(Surface &band, Dest &dest, size_t frame_height, DrawFn &&draw)
Renders a frame taller than its framebuffer, band by band.
void render_banded(Surface &band, Dest &dest, size_t frame_height, DrawFn &&draw)
Renders a frame taller than its framebuffer, band by band.
void draw_hline(Surface &surface, size_t x, size_t y, size_t length, typename Surface::pixel_type ink) noexcept
Draws a horizontal line with the given ink.
void draw_text(Surface &surface, const font::mono_font &font, size_t x, size_t y, std::string_view text, typename Surface::pixel_type ink, unsigned scale=1) noexcept
Draws text with the given ink.
void fill_rect(Surface &surface, size_t x, size_t y, size_t width, size_t height, typename Surface::pixel_type ink) noexcept
Fills a rectangle with the given ink.
void draw_vline(Surface &surface, size_t x, size_t y, size_t length, typename Surface::pixel_type ink) noexcept
Draws a vertical line with the given ink.
void draw_rect(Surface &surface, size_t x, size_t y, size_t width, size_t height, typename Surface::pixel_type ink) noexcept
Outlines a rectangle with the given ink.
void draw_line(Surface &surface, size_t x0, size_t y0, size_t x1, size_t y1, typename Surface::pixel_type ink) noexcept
Draws a straight line between two points with the given ink.
Drawing primitives and the pixel surface concept.
constexpr std::unexpected< std::error_code > error(E e) noexcept
Creates an unexpected error from an error code enum.
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
@ invalid_arg
Invalid argument.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
A fixed-cell monochrome bitmap font.
constexpr size_t advance(char) const noexcept
Returns the horizontal distance the cursor moves after c.
constexpr const uint8_t * glyph(char c) const noexcept
Returns a pointer to the glyph bitmap for c.
uint8_t width
Glyph cell width in pixels.
constexpr size_t bytes_per_row() const noexcept
Returns the number of bytes in one glyph row.
constexpr bool contains(char c) const noexcept
Returns true if the font has a glyph for c.
uint8_t height
Glyph cell height in pixels.