idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
mono_framebuffer.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
13#include <idfxx/error>
14#include <idfxx/lcd/panel>
15
16#include <algorithm>
17#include <cstddef>
18#include <cstdint>
19#include <span>
20#include <vector>
21
26namespace idfxx::lcd {
27
50public:
52 using pixel_type = bool;
53
54#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
64 [[nodiscard]] mono_framebuffer(size_t width, size_t height)
66#endif
67
77 [[nodiscard]] static result<mono_framebuffer> make(size_t width, size_t height) {
78 if (width == 0 || height == 0 || height % 8 != 0) {
80 }
81 return mono_framebuffer{width, height, std::vector<uint8_t>(width * height / 8)};
82 }
83
85 [[nodiscard]] size_t width() const noexcept { return _width; }
86
88 [[nodiscard]] size_t height() const noexcept { return _height; }
89
99 void set_pixel(size_t x, size_t y, bool on) noexcept {
100 if (x >= _width || y >= _height) {
101 return;
102 }
103 uint8_t& byte = _data[(y / 8) * _width + x];
104 uint8_t mask = static_cast<uint8_t>(1u << (y % 8));
105 if (on) {
106 byte |= mask;
107 } else {
108 byte &= static_cast<uint8_t>(~mask);
109 }
110 }
111
119 [[nodiscard]] bool get_pixel(size_t x, size_t y) const noexcept {
120 if (x >= _width || y >= _height) {
121 return false;
122 }
123 return (_data[(y / 8) * _width + x] & (1u << (y % 8))) != 0;
124 }
125
130 void fill(bool on) noexcept { std::ranges::fill(_data, on ? uint8_t{0xFF} : uint8_t{0x00}); }
131
133 void clear() noexcept { fill(false); }
134
144 [[nodiscard]] std::span<const uint8_t> data() const noexcept { return _data; }
145
146#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
157 void flush(panel& panel) const { unwrap(try_flush(panel)); }
158
173 void flush_rows(panel& panel, size_t y_start, size_t y_end) const { unwrap(try_flush_rows(panel, y_start, y_end)); }
174
193 void flush_region(panel& panel, size_t x_start, size_t y_start, size_t x_end, size_t y_end) const {
194 unwrap(try_flush_region(panel, x_start, y_start, x_end, y_end));
195 }
196#endif
197
207 [[nodiscard]] result<void> try_flush(panel& panel) const {
208 return panel.try_draw_bitmap(0, 0, static_cast<int>(_width), static_cast<int>(_height), _data.data());
209 }
210
225 [[nodiscard]] result<void> try_flush_rows(panel& panel, size_t y_start, size_t y_end) const {
226 return try_flush_region(panel, 0, y_start, _width, y_end);
227 }
228
247 [[nodiscard]] result<void>
248 try_flush_region(panel& panel, size_t x_start, size_t y_start, size_t x_end, size_t y_end) const {
249 if (x_start >= x_end || x_end > _width || y_start >= y_end || y_end > _height) {
250 return error(errc::invalid_arg);
251 }
252 size_t first_page = y_start / 8;
253 size_t end_page = (y_end + 7) / 8;
254 if (x_start == 0 && x_end == _width) {
255 // In the page-major layout a full-width band is contiguous, so a
256 // single transfer covers all its pages.
257 return panel.try_draw_bitmap(
258 0,
259 static_cast<int>(first_page * 8),
260 static_cast<int>(_width),
261 static_cast<int>(end_page * 8),
262 _data.data() + first_page * _width
263 );
264 }
265 for (size_t page = first_page; page < end_page; ++page) {
266 auto drawn = panel.try_draw_bitmap(
267 static_cast<int>(x_start),
268 static_cast<int>(page * 8),
269 static_cast<int>(x_end),
270 static_cast<int>((page + 1) * 8),
271 _data.data() + page * _width + x_start
272 );
273 if (!drawn) {
274 return drawn;
275 }
276 }
277 return {};
278 }
279
280private:
281 mono_framebuffer(size_t width, size_t height, std::vector<uint8_t> data)
282 : _width(width)
283 , _height(height)
284 , _data(std::move(data)) {}
285
286 size_t _width;
287 size_t _height;
288 std::vector<uint8_t> _data;
289};
290
291} // namespace idfxx::lcd
In-memory framebuffer for monochrome (1 bit per pixel) displays.
bool get_pixel(size_t x, size_t y) const noexcept
Returns the state of a single pixel.
void set_pixel(size_t x, size_t y, bool on) noexcept
Sets or clears a single pixel.
void clear() noexcept
Clears every pixel (equivalent to fill(false)).
void flush(panel &panel) const
Draws the full framebuffer to a panel.
bool pixel_type
The value type written by set_pixel.
size_t height() const noexcept
Returns the height in pixels.
static result< mono_framebuffer > make(size_t width, size_t height)
Creates a framebuffer of the given dimensions, with all pixels off.
void fill(bool on) noexcept
Sets every pixel to the given state.
void flush_region(panel &panel, size_t x_start, size_t y_start, size_t x_end, size_t y_end) const
Draws a rectangular region of the framebuffer to a panel.
result< void > try_flush_rows(panel &panel, size_t y_start, size_t y_end) const
Draws a horizontal band of the framebuffer to a panel.
void flush_rows(panel &panel, size_t y_start, size_t y_end) const
Draws a horizontal band of the framebuffer to a panel.
size_t width() const noexcept
Returns the width in pixels.
result< void > try_flush_region(panel &panel, size_t x_start, size_t y_start, size_t x_end, size_t y_end) const
Draws a rectangular region of the framebuffer to a panel.
mono_framebuffer(size_t width, size_t height)
Creates a framebuffer of the given dimensions, with all pixels off.
result< void > try_flush(panel &panel) const
Draws the full framebuffer to a panel.
std::span< const uint8_t > data() const noexcept
Returns the raw page-packed pixel data.
Abstract base class for LCD panels.
Definition panel.hpp:47
result< void > try_draw_bitmap(int x_start, int y_start, int x_end, int y_end, const void *color_data)
Draws bitmap data to a region of the display.
Definition panel.hpp:163
LCD driver classes.
Definition color.hpp:21
constexpr std::unexpected< std::error_code > error(E e) noexcept
Creates an unexpected error from an error code enum.
Definition error.hpp:187
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:307
@ invalid_arg
Invalid argument.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120