5. Display - вывод на панель
Низкоуровневый RGB565-интерфейс. В приложении используется через plat->display().
| Метод |
Описание |
bool begin(uint8_t rotation) |
Инициализация панели (обычно вызывается через Platform::beginDisplay) |
bool setRotation(uint8_t rotation) |
Поворот 0..3 на лету |
uint16_t width() const / uint16_t height() const |
Текущее разрешение с учётом поворота |
void fillScreen565(uint16_t color565) |
Заливка всего экрана |
void writeRect565(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pixels, int32_t stridePixels) |
Вывод прямоугольника. Синхронно: возвращается, когда данные уже ушли в панель |
void writeRect565Async(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pixels, int32_t stridePixels) |
То же через DMA: ставит передачу в очередь и возвращается сразу |
void waitDMA() |
Дождаться завершения асинхронных передач |
Ключевые понятия
stridePixels - шаг строки источника в пикселях. Позволяет выводить произвольное окно из большого буфера кадра: writeRect565(100, 50, 60, 40, frame, frameWidth). Для плотно упакованного источника передайте w.
- Синхронный путь просто и предсказуемо: вернулись - можно менять буфер.
- Асинхронный путь освобождает CPU для отрисовки следующего кадра. Два правила:
- буфер-источник должен оставаться валидным до
waitDMA() (DMA читает его прямо из памяти);
- перед повторным использованием буфера вызовите
waitDMA().
- При
swap = true асинхронный путь прозрачно прогоняет данные через двойной DMA-буфер (копирование со свопом): цвета верны, но копирование ложится на CPU.
Пример
Поставить кадр N в очередь → рисовать кадр N+1 в другой буфер → waitDMA() → поменять буферы:
Sprite bufA(plat), bufB(plat);
if (!bufA.createSprite(w, h) || !bufB.createSprite(w, h))
return;
Sprite *front = &bufA; // его сейчас передаёт DMA
Sprite *back = &bufB; // в него рисуем
while (!plat->shouldQuit())
{
renderScene(*back); // CPU рисует, пока DMA занят
display->waitDMA(); // предыдущий кадр ушёл
display->writeRect565Async(0, 0, w, h,
static_cast<const uint16_t *>(back->getBuffer()), w);
std::swap(front, back); // теперь рисуем в другой буфер
}
Драйверы
| Драйвер |
Формат |
Макс. частота |
Особенности |
| ST7789 / ST7796 |
RGB565 |
80 МГц |
Общий шаблонный движок, очередь DMA-транзакций с двойной буферизацией |
| ILI9488 |
RGB666 |
60 МГц |
Конвейер с конвертацией 565 → 666 |
6. Sprite - offscreen-графика
Модуль включается опцией PIPCORE_ENABLE_GRAPHICS (по умолчанию включён вместе с драйвером дисплея).
Sprite - изображение в RAM с клиппингом и быстрым блиттингом. Память выделяется через Platform::alloc (внутренняя RAM в приоритете) и освобождается в деструкторе или deleteSprite(). Копировать спрайт нельзя, для обмена буферами есть swap().
Sprite sp(plat);
if (!sp.createSprite(128, 64))
{
// не хватило памяти
return;
}
sp.fillScreen(Sprite::color565(0, 0, 0));
sp.fillRect(10, 10, 40, 20, Sprite::color565(255, 128, 0));
sp.writeToDisplay(*plat->display(), 0, 0, 128, 64);
Создание и служебные методы
| Метод |
Описание |
Sprite() / explicit Sprite(Platform *platform) |
Конструктор. Платформа нужна для выделения памяти - передайте её здесь или через setPlatform() |
bool createSprite(int16_t w, int16_t h) |
Выделить буфер w × h. false - не хватило памяти |
void deleteSprite() |
Освободить буфер |
int16_t width() const / int16_t height() const |
Размер |
void setPlatform(Platform *platform) |
Сменить платформу-аллокатор |
void *getBuffer() / const void *getBuffer() const |
Прямой доступ к пикселям (для своих ядер отрисовки). Буфер хранит значения в байтовом порядке, готовом к DMA (после swap16) |
void swap(Sprite &other) |
Обменять буферы без копирования (удобно для двойной буферизации) |
Рисование
| Метод |
Описание |
void fillScreen(uint16_t color565) |
Залить весь спрайт |
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color565) |
Залитый прямоугольник |
void drawPixel(int16_t x, int16_t y, uint16_t color565) |
Пиксель. Вне клип-зоны молча игнорируется |
void pushImage(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pixels565) |
Вставить плотно упакованное изображение |
Вывод
| Метод |
Описание |
void writeToDisplay(Display &display, int16_t x, int16_t y, int16_t w, int16_t h) const |
Вывести область на дисплей: x, y - позиция на дисплее, w, h - размер области |
void pushSprite(Sprite *dst, int16_t x, int16_t y) const |
Спрайт на спрайт (композиция offscreen-сцен) |
Клиппинг
| Метод |
Описание |
void setClipRect(int16_t x, int16_t y, int16_t w, int16_t h) |
Зона отсечения: всё вне неё не рисуется. Удобно для окон и скролла |
void getClipRect(int32_t *x, int32_t *y, int32_t *w, int32_t *h) const |
Текущая зона |
SpriteClip clipRegion(int16_t x, int16_t y, int16_t w, int16_t h) const |
Пересечение прямоугольника с клип-зоной - для собственных циклов отрисовки |
struct SpriteClip
{
int16_t rx1, ry1; // левый верхний угол видимой части
int16_t cw, ch; // её размер
bool visible; // false - пересечение пусто
};
Цветовые утилиты
static constexpr - вызываются без объекта: Sprite::color565(...).
| Метод |
Описание |
uint16_t color565(uint8_t r, uint8_t g, uint8_t b) |
RGB888 → RGB565 |
uint16_t swap16(uint16_t v) |
Байтовый своп |
uint16_t blend565(uint16_t bg, uint16_t fg, uint8_t alpha) |
Альфа-смешение, alpha 0…255 (0 - фон, 255 - передний план) |
uint8_t u8clamp(int v) |
Ограничение значения диапазоном 0…255 |