mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 15:17:48 +01:00
8bit draw
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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 = {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cardboy/sdk/display_spec.hpp>
|
||||
#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<EspFramebuff
|
||||
public:
|
||||
EspFramebuffer() = default;
|
||||
|
||||
[[nodiscard]] int width_impl() const;
|
||||
[[nodiscard]] int height_impl() const;
|
||||
void drawPixel_impl(int x, int y, bool on);
|
||||
[[nodiscard]] int width_impl() const { return cardboy::sdk::kDisplayWidth; }
|
||||
[[nodiscard]] int height_impl() const { return cardboy::sdk::kDisplayHeight; }
|
||||
void drawPixel_impl(int x, int y, bool on) { SMD::set_pixel(x, y, on); }
|
||||
void drawBits8_impl(int x, int y, std::uint8_t bits) { SMD::set_pixel_8(x, y, bits); }
|
||||
void clear_impl(bool on);
|
||||
void frameReady_impl();
|
||||
void sendFrame_impl(bool clearAfterSend);
|
||||
|
||||
@@ -58,14 +58,14 @@ public:
|
||||
void beepLevelUp(int level) override { Buzzer::get().beepLevelUp(level); }
|
||||
void beepGameOver() override { Buzzer::get().beepGameOver(); }
|
||||
|
||||
void setMuted(bool muted) override { Buzzer::get().setMuted(muted); }
|
||||
void toggleMuted() override { Buzzer::get().toggleMuted(); }
|
||||
void setMuted(bool muted) override { Buzzer::get().setMuted(muted); }
|
||||
void toggleMuted() override { Buzzer::get().toggleMuted(); }
|
||||
[[nodiscard]] bool isMuted() const override { return Buzzer::get().isMuted(); }
|
||||
};
|
||||
|
||||
class EspRuntime::BatteryService final : public cardboy::sdk::IBatteryMonitor {
|
||||
public:
|
||||
[[nodiscard]] bool hasData() const override { return true; }
|
||||
[[nodiscard]] bool hasData() const override { return true; }
|
||||
[[nodiscard]] float voltage() const override { return BatMon::get().get_voltage(); }
|
||||
[[nodiscard]] float charge() const override { return BatMon::get().get_charge(); }
|
||||
[[nodiscard]] float current() const override { return BatMon::get().get_current(); }
|
||||
@@ -114,14 +114,14 @@ public:
|
||||
|
||||
class EspRuntime::PowerService final : public cardboy::sdk::IPowerManager {
|
||||
public:
|
||||
void setSlowMode(bool enable) override { PowerHelper::get().set_slow(enable); }
|
||||
void setSlowMode(bool enable) override { PowerHelper::get().set_slow(enable); }
|
||||
[[nodiscard]] bool isSlowMode() const override { return PowerHelper::get().is_slow(); }
|
||||
};
|
||||
|
||||
class EspRuntime::FilesystemService final : public cardboy::sdk::IFilesystem {
|
||||
public:
|
||||
bool mount() override { return FsHelper::get().mount() == ESP_OK; }
|
||||
[[nodiscard]] bool isMounted() const override { return FsHelper::get().isMounted(); }
|
||||
bool mount() override { return FsHelper::get().mount() == ESP_OK; }
|
||||
[[nodiscard]] bool isMounted() const override { return FsHelper::get().isMounted(); }
|
||||
[[nodiscard]] std::string basePath() const override {
|
||||
const char* path = FsHelper::get().basePath();
|
||||
return path ? std::string(path) : std::string{};
|
||||
@@ -182,16 +182,6 @@ void EspRuntime::initializeHardware() {
|
||||
FsHelper::get().mount();
|
||||
}
|
||||
|
||||
int EspFramebuffer::width_impl() const { return cardboy::sdk::kDisplayWidth; }
|
||||
|
||||
int EspFramebuffer::height_impl() const { return cardboy::sdk::kDisplayHeight; }
|
||||
|
||||
void EspFramebuffer::drawPixel_impl(int x, int y, bool on) {
|
||||
if (x < 0 || y < 0 || x >= 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)
|
||||
|
||||
@@ -23,6 +23,9 @@ concept HasSendFrameImpl = requires(Impl& impl, bool flag) {
|
||||
{ impl.sendFrame_impl(flag) };
|
||||
};
|
||||
|
||||
template<typename Impl>
|
||||
concept HasDrawBits8Impl = requires(Impl& impl, int x, int y, std::uint8_t bits) { impl.drawBits8_impl(x, y, bits); };
|
||||
|
||||
template<typename Impl>
|
||||
concept HasFrameInFlightImpl = requires(const Impl& impl) {
|
||||
{ impl.frameInFlight_impl() } -> std::convertible_to<bool>;
|
||||
@@ -37,11 +40,19 @@ concept HasSleepMsImpl = requires(Impl& impl, std::uint32_t value) {
|
||||
template<typename Impl>
|
||||
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>) {
|
||||
impl().drawBits8_impl(x, y, bits);
|
||||
} else {
|
||||
defaultDrawBits8(x, y, bits);
|
||||
}
|
||||
}
|
||||
|
||||
void clear(bool on) {
|
||||
if constexpr (detail::HasClearImpl<Impl>) {
|
||||
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<std::uint8_t>(1u << (7 - col));
|
||||
const bool pixelOn = (bits & mask) != 0;
|
||||
drawPixel(x + col, y, pixelOn);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Impl>
|
||||
|
||||
@@ -41,6 +41,13 @@ template<typename Framebuffer>
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user