From 961453e28aa5f1b1295a033dfef8520b94d285f2 Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Sat, 11 Oct 2025 20:03:00 +0200 Subject: [PATCH] 8bit draw --- .../include/cardboy/backend/esp/display.hpp | 10 +++++++- .../include/cardboy/backend/esp_backend.hpp | 9 +++++--- .../backend-esp/src/esp_backend.cpp | 22 +++++------------- .../include/cardboy/sdk/platform.hpp | 23 +++++++++++++++++-- .../sdk/core/include/cardboy/gfx/font16x8.hpp | 7 ++++++ 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/Firmware/components/backend-esp/include/cardboy/backend/esp/display.hpp b/Firmware/components/backend-esp/include/cardboy/backend/esp/display.hpp index 98155c5..510eba7 100644 --- a/Firmware/components/backend-esp/include/cardboy/backend/esp/display.hpp +++ b/Firmware/components/backend-esp/include/cardboy/backend/esp/display.hpp @@ -13,7 +13,7 @@ #include #include #include - +#include namespace SMD { static constexpr size_t kLineBytes = DISP_WIDTH / 8; @@ -46,6 +46,14 @@ __attribute__((always_inline)) static void set_pixel(int x, int y, bool value) { } } +__attribute__((always_inline)) static void set_pixel_8(int x, int y, std::uint8_t value) { + assert(x >= 0 && x < DISP_WIDTH && y >= 0 && y < DISP_HEIGHT); + assert((x % 8) == 0); + unsigned lineIdx = 2 + kLineMultiSingle * y + (x / 8); + dma_buf[lineIdx] = ~value; +} + + extern "C" void s_spi_post_cb(spi_transaction_t* trans); static inline spi_device_interface_config_t _devcfg = { diff --git a/Firmware/components/backend-esp/include/cardboy/backend/esp_backend.hpp b/Firmware/components/backend-esp/include/cardboy/backend/esp_backend.hpp index a9df431..40822ab 100644 --- a/Firmware/components/backend-esp/include/cardboy/backend/esp_backend.hpp +++ b/Firmware/components/backend-esp/include/cardboy/backend/esp_backend.hpp @@ -1,5 +1,7 @@ #pragma once +#include +#include "cardboy/backend/esp/display.hpp" #include "cardboy/sdk/platform.hpp" #include "cardboy/sdk/services.hpp" @@ -14,9 +16,10 @@ class EspFramebuffer final : public cardboy::sdk::FramebufferFacade= width_impl() || y >= height_impl()) - return; - SMD::set_pixel(x, y, on); -} - void EspFramebuffer::clear_impl(bool on) { for (int y = 0; y < height_impl(); ++y) for (int x = 0; x < width_impl(); ++x) diff --git a/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp b/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp index 56b5e5a..6cb9fd9 100644 --- a/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp +++ b/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp @@ -23,6 +23,9 @@ concept HasSendFrameImpl = requires(Impl& impl, bool flag) { { impl.sendFrame_impl(flag) }; }; +template +concept HasDrawBits8Impl = requires(Impl& impl, int x, int y, std::uint8_t bits) { impl.drawBits8_impl(x, y, bits); }; + template concept HasFrameInFlightImpl = requires(const Impl& impl) { { impl.frameInFlight_impl() } -> std::convertible_to; @@ -37,11 +40,19 @@ concept HasSleepMsImpl = requires(Impl& impl, std::uint32_t value) { template class FramebufferFacade { public: - [[nodiscard]] int width() const { return impl().width_impl(); } - [[nodiscard]] int height() const { return impl().height_impl(); } + [[nodiscard]] __attribute__((always_inline)) int width() const { return impl().width_impl(); } + [[nodiscard]] __attribute__((always_inline)) int height() const { return impl().height_impl(); } __attribute__((always_inline)) void drawPixel(int x, int y, bool on) { impl().drawPixel_impl(x, y, on); } + __attribute__((always_inline)) void drawBits8(int x, int y, std::uint8_t bits) { + if constexpr (detail::HasDrawBits8Impl) { + impl().drawBits8_impl(x, y, bits); + } else { + defaultDrawBits8(x, y, bits); + } + } + void clear(bool on) { if constexpr (detail::HasClearImpl) { impl().clear_impl(on); @@ -79,6 +90,14 @@ private: for (int x = 0; x < width(); ++x) drawPixel(x, y, on); } + + void defaultDrawBits8(int x, int y, std::uint8_t bits) { + for (int col = 0; col < 8; ++col) { + const std::uint8_t mask = static_cast(1u << (7 - col)); + const bool pixelOn = (bits & mask) != 0; + drawPixel(x + col, y, pixelOn); + } + } }; template diff --git a/Firmware/sdk/core/include/cardboy/gfx/font16x8.hpp b/Firmware/sdk/core/include/cardboy/gfx/font16x8.hpp index 96a8ee7..8ec0559 100644 --- a/Firmware/sdk/core/include/cardboy/gfx/font16x8.hpp +++ b/Firmware/sdk/core/include/cardboy/gfx/font16x8.hpp @@ -41,6 +41,13 @@ template inline void drawGlyph(Framebuffer& fb, int x, int y, char ch, int scale = 1, bool on = true, Rotation rotation = Rotation::None) { const auto& rows = glyphBitmap(ch); + if (rotation == Rotation::None && scale == 1 && on && ((x % 8) == 0)) { + for (int row = 0; row < kGlyphHeight; ++row) { + const uint8_t rowBits = rows[row]; + fb.drawBits8(x, y + row, rowBits); + } + return; + } for (int row = 0; row < kGlyphHeight; ++row) { const uint8_t rowBits = rows[row]; for (int col = 0; col < kGlyphWidth; ++col) {