C++: implement (mostly) non-allocating parser that immediately renders

pull/1/head^2
Christian Seiler 4 weeks ago
parent 9237b2b1ac
commit b9ff412df5
  1. 149
      cpp/clivis/main.cpp
  2. 4
      cpp/src/CMakeLists.txt
  3. 6
      cpp/src/monoformat_fontreader.cpp
  4. 2
      cpp/src/monoformat_fontreader.hpp
  5. 4
      cpp/src/monoformat_parsehelpers.hpp
  6. 1053
      cpp/src/monoformat_parseonly.cpp
  7. 15
      cpp/src/monoformat_parseonly.hpp
  8. 103
      cpp/src/monoformat_schema.cpp
  9. 77
      cpp/src/monoformat_schema.hpp
  10. 128
      cpp/src/monoformat_structured.cpp
  11. 66
      cpp/src/monoformat_structured.hpp

@ -1,47 +1,52 @@
#include <monoformat_fontreader.hpp> #include <monoformat_fontreader.hpp>
#include <monoformat_structured.hpp> #include <monoformat_structured.hpp>
#include <monoformat_parseonly.hpp>
#include <iostream>
#include <sstream> #include <sstream>
#include <fstream>
#include <iostream>
#include <vector> #include <vector>
#include <cstdint>
#include <filesystem>
#include <stdexcept>
#include <atomic>
#include <csignal>
#include <thread>
#include <chrono>
using namespace monoformat; using namespace monoformat;
constexpr static std::uint16_t const ScreenWidth = 120; constexpr static std::uint16_t const ScreenWidth = 120;
constexpr static std::uint16_t const ScreenHeight = 60; constexpr static std::uint16_t const ScreenHeight = 60;
int main() { static std::atomic<bool> g_ctrlCPressed;
auto fontData = findEmbeddedFont("NokiaSmallPlain_tf");
if (!fontData.size()) {
std::cerr << "Error loading font!\n" << std::flush;
return 1;
}
auto fontData2 = findEmbeddedFont("5x7_mf");
if (!fontData2.size()) {
std::cerr << "Error loading font!\n" << std::flush;
return 1;
}
std::vector<std::byte> memory; static void handleCtrlC(int) {
memory.resize((ScreenWidth * ScreenHeight + 7) / 8); g_ctrlCPressed.store(true, std::memory_order_relaxed);
MemoryOneBitBuffer screen{memory, ScreenWidth, ScreenHeight}; }
auto renderer = FontRenderer{fontData}.withIgnoreUnknownChars(true); template<typename Container>
auto ret = renderer.render("Hallo Welt! ggg äöüß é è ê", {0, renderer.lineHeight() - 1}, screen, true, false); static Container readEntireFile(std::filesystem::path const& fileName) {
if (!ret) { std::ifstream fileReader(fileName, std::ios::binary | std::ios::ate | std::ios::in);
std::cerr << "Error rendering.\n" << std::flush; if (!fileReader) {
return 2; std::ostringstream buf;
} buf << "Could not open \"" << fileName << "\" for reading";
throw std::runtime_error(buf.str());
auto renderer2 = FontRenderer{fontData2}.withIgnoreUnknownChars(true);
ret = renderer2.render("Hallo2", {0, renderer2.lineHeight() - 1 + renderer.lineHeight()}, screen, true, false);
if (!ret) {
std::cerr << "Error rendering.\n" << std::flush;
return 2;
} }
auto fileSize = fileReader.tellg();
fileReader.seekg(std::ios::beg);
typename Container::size_type scalarSize = sizeof(typename Container::value_type);
Container content((static_cast<typename Container::size_type>(fileSize) + scalarSize - 1) / scalarSize,
static_cast<typename Container::value_type>(0));
fileReader.read(reinterpret_cast<char*>(&content[0]), static_cast<std::size_t>(fileSize));
return content;
}
std::cerr << "Bbox height: " << ret->boundingBox->size.height << std::endl; static void clearScreen() {
std::cout << "\x1b[1J\x1b[1;1H" << std::flush;
}
static void renderScreeen(monoformat::OneBitBufferInterface const& imageBuffer) {
std::uint16_t const w = ScreenWidth; std::uint16_t const w = ScreenWidth;
std::uint16_t const h = ScreenHeight / 2; std::uint16_t const h = ScreenHeight / 2;
@ -54,8 +59,8 @@ int main() {
for (std::uint16_t y = 0; y < h; ++y) { for (std::uint16_t y = 0; y < h; ++y) {
buf << "\xE2\x94\x82"; buf << "\xE2\x94\x82";
for (std::uint16_t x = 0; x < w; ++x) { for (std::uint16_t x = 0; x < w; ++x) {
bool const pxUpperSet = screen.isPixelSet(x, 2 * y + 0); bool const pxUpperSet = imageBuffer.isPixelSet(x, 2 * y + 0);
bool const pxLowerSet = screen.isPixelSet(x, 2 * y + 1); bool const pxLowerSet = imageBuffer.isPixelSet(x, 2 * y + 1);
if (pxUpperSet && pxLowerSet) { if (pxUpperSet && pxLowerSet) {
buf << "\xE2\x96\x88"; buf << "\xE2\x96\x88";
} else if (pxUpperSet) { } else if (pxUpperSet) {
@ -71,7 +76,7 @@ int main() {
if (ScreenHeight % 1) { if (ScreenHeight % 1) {
buf << "\xE2\x94\x82"; buf << "\xE2\x94\x82";
for (std::uint16_t x = 0; x < w; ++x) { for (std::uint16_t x = 0; x < w; ++x) {
bool const pxUpperSet = screen.isPixelSet(x, ScreenHeight - 1); bool const pxUpperSet = imageBuffer.isPixelSet(x, ScreenHeight - 1);
if (pxUpperSet) { if (pxUpperSet) {
buf << "\xF0\x9F\xAC\x8E"; buf << "\xF0\x9F\xAC\x8E";
} else { } else {
@ -86,6 +91,88 @@ int main() {
} }
buf << "\xE2\x94\x98\n"; buf << "\xE2\x94\x98\n";
std::cout << buf.str(); std::cout << buf.str();
}
static void showContents(monoformat::File const& file, std::size_t tick, std::int64_t timestamp, std::span<monoformat::CustomFontSection const*> customFonts) {
monoformat::ImageElement imageBufferElement{0, 0, ScreenWidth, ScreenHeight};
auto imageBuffer = imageBufferElement.image();
for (auto const& section : file.sections) {
if (auto sec = dynamic_cast<monoformat::AlwaysDrawnSection*>(section.get())) {
for (std::size_t i = 0; i < sec->elementCount(); ++i) {
sec->elementAt(i)->drawTo(&imageBuffer, tick, timestamp, customFonts);
}
} else if (auto sec = dynamic_cast<monoformat::TimeBasedDrawnSection*>(section.get())) {
for (std::size_t i = 0; i < sec->elementCount(); ++i) {
sec->elementAt(i)->drawTo(&imageBuffer, tick, timestamp, customFonts);
}
}
}
renderScreeen(imageBuffer);
}
static void showContents2(std::span<std::byte const> data, std::size_t tick, std::int64_t timestamp) {
std::vector<std::byte> buffer;
buffer.resize((ScreenWidth * ScreenHeight + 8 - 1) / 8);
MemoryOneBitBuffer imageBuffer{buffer, ScreenWidth, ScreenHeight};
auto ret = parseAndApply(data, &imageBuffer, ScreenWidth, ScreenHeight, true, tick, timestamp);
if (!ret) {
std::cerr << "Parse & apply error\n";
}
renderScreeen(imageBuffer);
}
int main(int argc, char** argv) {
if (argc != 2 || !argv[1]) {
std::ostringstream buf;
buf << "Usage: " << argv[0] << " filename\n";
std::cerr << buf.str();
return 1;
}
if (std::string_view{argv[1]} == "--help") {
std::ostringstream buf;
buf << "Usage: " << argv[0] << " filename\n";
std::cout << buf.str() << std::flush;
return 0;
}
try {
auto contents = readEntireFile<std::vector<std::byte>>(argv[1]);
auto file = monoformat::parseFile(contents);
if (!file) {
std::ostringstream buf;
buf << "Parse error while processing the file \"" << argv[1] << "\"";
throw std::runtime_error(buf.str());
}
std::vector<monoformat::CustomFontSection const*> customFonts;
for (auto const& section : file->sections) {
if (auto fs = dynamic_cast<monoformat::CustomFontSection const*>(section.get())) {
customFonts.push_back(fs);
}
}
std::signal(SIGINT, &handleCtrlC);
std::signal(SIGTERM, &handleCtrlC);
std::size_t tick = 0;
while (!g_ctrlCPressed.load(std::memory_order_relaxed)) {
clearScreen();
//showContents(*file, tick, time(nullptr), customFonts);
showContents2(contents, tick, time(nullptr));
std::ostringstream buf;
buf << "Animation Tick: " << tick << "\n";
std::cout << buf.str() << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds{40});
++tick;
}
} catch (std::exception& e) {
std::ostringstream buf;
buf << argv[0] << ": " << e.what() << "\n";
std::cerr << buf.str();
return 2;
}
return 0; return 0;
} }

@ -1,10 +1,14 @@
set(monoformat_SOURCES set(monoformat_SOURCES
monoformat_schema.cpp
monoformat_structured.cpp monoformat_structured.cpp
monoformat_parseonly.cpp
monoformat_fontreader.cpp monoformat_fontreader.cpp
) )
set(monoformat_HEADERS set(monoformat_HEADERS
monoformat_schema.hpp
monoformat_structured.hpp monoformat_structured.hpp
monoformat_parsehelpers.hpp monoformat_parsehelpers.hpp
monoformat_parseonly.hpp
monoformat_fontreader.hpp monoformat_fontreader.hpp
monoformat_gfx.hpp monoformat_gfx.hpp
monoformat_utf8.hpp monoformat_utf8.hpp

@ -5,10 +5,10 @@ namespace monoformat {
#include "u8g2_font_NokiaSmallPlain_tf.inc.cpp" #include "u8g2_font_NokiaSmallPlain_tf.inc.cpp"
#include "u8g2_font_5x7_mf.inc.cpp" #include "u8g2_font_5x7_mf.inc.cpp"
std::span<std::byte const> findEmbeddedFont(std::string_view name) { std::span<std::byte const> findEmbeddedFont(std::size_t fontIndex) {
if (name == "NokiaSmallPlain_tf") { if (fontIndex == 0) {
return std::as_bytes(std::span{u8g2_font_NokiaSmallPlain_tf_u8g2font, u8g2_font_NokiaSmallPlain_tf_u8g2font_len}); return std::as_bytes(std::span{u8g2_font_NokiaSmallPlain_tf_u8g2font, u8g2_font_NokiaSmallPlain_tf_u8g2font_len});
} else if (name == "5x7_mf") { } else if (fontIndex == 1) {
return std::as_bytes(std::span{u8g2_font_5x7_mf_u8g2font, u8g2_font_5x7_mf_u8g2font_len}); return std::as_bytes(std::span{u8g2_font_5x7_mf_u8g2font, u8g2_font_5x7_mf_u8g2font_len});
} else { } else {
return {}; return {};

@ -652,7 +652,7 @@ inline FontRenderer::FontRenderer(std::span<std::byte const> fontData)
{ {
} }
extern std::span<std::byte const> findEmbeddedFont(std::string_view name); extern std::span<std::byte const> findEmbeddedFont(std::size_t fontIndex);
} // namespace monoformat } // namespace monoformat

@ -328,8 +328,8 @@ inline std::size_t writeU64BE(std::span<std::byte>& target, std::size_t pos, std
inline std::size_t writeBuffer(std::span<std::byte>& target, std::size_t pos, std::span<std::byte const> value) { inline std::size_t writeBuffer(std::span<std::byte>& target, std::size_t pos, std::span<std::byte const> value) {
if ((pos + value.size()) > target.size()) { if ((pos + value.size()) > target.size()) {
if (pos < value.size()) { if (pos < target.size()) {
std::size_t const n = value.size() - pos; std::size_t const n = target.size() - pos;
std::copy(value.begin(), value.begin() + n, target.begin() + pos); std::copy(value.begin(), value.begin() + n, target.begin() + pos);
} }
} else { } else {

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
#ifndef MONOFORMAT_PARSEONLY_HPP
#define MONOFORMAT_PARSEONLY_HPP
#include "monoformat_parsehelpers.hpp"
#include "monoformat_schema.hpp"
namespace monoformat {
std::expected<void, ParseError> parseAndApply(std::span<std::byte const> data, OneBitBufferInterface* buffer,
std::uint16_t screenWidth, std::uint16_t screenHeight,
bool isFront, std::size_t animationTick, std::int64_t currentTimestamp);
} // namespace monoformat
#endif // MONOFORMAT_PARSEONLY_HPP

@ -0,0 +1,103 @@
#include "monoformat_schema.hpp"
#include <tuple>
namespace monoformat {
MemoryOneBitBuffer::MemoryOneBitBuffer(std::span<std::byte> buffer, std::uint16_t width, std::uint16_t height)
: m_width{width}
, m_height{height}
, m_buffer{buffer}
{
std::size_t expectedSize = (m_width * m_height + 8 - 1) / 8;
if (m_buffer.size() < expectedSize) {
m_width = 0;
m_height = 0;
}
}
MemoryOneBitBuffer::~MemoryOneBitBuffer() {
}
bool MemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const {
if (x >= m_width || y >= m_height) {
return false;
}
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8;
return ((static_cast<std::uint8_t>(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01;
}
void MemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) {
if (x >= m_width || y >= m_height) {
return;
}
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8;
if (value) {
m_buffer[byteIndex] = static_cast<std::byte>(static_cast<std::uint8_t>(m_buffer[byteIndex]) | (1u << bitIndex));
} else {
m_buffer[byteIndex] = static_cast<std::byte>(static_cast<std::uint8_t>(m_buffer[byteIndex]) & ~(1u << bitIndex));
}
}
ConstMemoryOneBitBuffer::ConstMemoryOneBitBuffer(std::span<std::byte const> buffer, std::uint16_t width, std::uint16_t height)
: m_width{width}
, m_height{height}
, m_buffer{buffer}
{
std::size_t expectedSize = (m_width * m_height + 8 - 1) / 8;
if (m_buffer.size() < expectedSize) {
m_width = 0;
m_height = 0;
}
}
ConstMemoryOneBitBuffer::~ConstMemoryOneBitBuffer() {
}
bool ConstMemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const {
if (x >= m_width || y >= m_height) {
return false;
}
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8;
return ((static_cast<std::uint8_t>(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01;
}
void ConstMemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) {
std::ignore = x;
std::ignore = y;
std::ignore = value;
}
ClippedImage::ClippedImage(OneBitBufferInterface* underlying, std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height)
: m_underlying{underlying}
, m_x{x}
, m_y{y}
, m_width{width}
, m_height{height}
{
}
ClippedImage::~ClippedImage() {
}
bool ClippedImage::isPixelSet(std::uint16_t x, std::uint16_t y) const {
if (x >= m_width || y >= m_height) {
return false;
}
return m_underlying->isPixelSet(x + m_x, y + m_y);
}
void ClippedImage::setPixel(std::uint16_t x, std::uint16_t y, bool value) {
if (x >= m_width || y >= m_height) {
return;
}
m_underlying->setPixel(x + m_x, y + m_y, value);
}
} // namespace monoformat

@ -0,0 +1,77 @@
#ifndef MONOFORMAT_SCHEMA_HPP
#define MONOFORMAT_SCHEMA_HPP
#include <cstddef>
#include <cstdint>
#include <span>
namespace monoformat {
enum class SectionType {
AlwaysDrawn = 1,
TimeBasedDrawn = 2,
CustomFont = 32,
};
enum class ElementType {
Image = 1,
Animation = 2,
HScrollImage = 3,
VScrollImage = 4,
Line = 5,
ClippedText = 16,
HScrollText = 17,
//VScrollText = 18,
CurrentTime = 32,
};
enum class LineStyle : std::uint8_t {
Solid = 0,
};
struct OneBitBufferInterface {
using Color = bool;
virtual ~OneBitBufferInterface() = default;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const = 0;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) = 0;
};
struct MemoryOneBitBuffer : public OneBitBufferInterface {
MemoryOneBitBuffer(std::span<std::byte> buffer, std::uint16_t width, std::uint16_t height);
virtual ~MemoryOneBitBuffer() override;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const override;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) override;
private:
std::uint16_t m_width{};
std::uint16_t m_height{};
std::span<std::byte> m_buffer;
};
struct ConstMemoryOneBitBuffer : public OneBitBufferInterface {
ConstMemoryOneBitBuffer(std::span<std::byte const> buffer, std::uint16_t width, std::uint16_t height);
virtual ~ConstMemoryOneBitBuffer() override;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const override;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) override;
private:
std::uint16_t m_width{};
std::uint16_t m_height{};
std::span<std::byte const> m_buffer;
};
struct ClippedImage : public OneBitBufferInterface {
ClippedImage(OneBitBufferInterface* underlying, std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height);
virtual ~ClippedImage() override;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const override;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) override;
private:
OneBitBufferInterface* m_underlying{};
std::uint16_t m_x{};
std::uint16_t m_y{};
std::uint16_t m_width{};
std::uint16_t m_height{};
};
} // namespace monoformat
#endif // MONOFORMAT_SCHEMA_HPP

@ -5,102 +5,6 @@
namespace monoformat { namespace monoformat {
MemoryOneBitBuffer::MemoryOneBitBuffer(std::span<std::byte> buffer, std::uint16_t width, std::uint16_t height)
: m_width{width}
, m_height{height}
, m_buffer{buffer}
{
std::size_t expectedSize = (m_width * m_height + 8 - 1) / 8;
if (m_buffer.size() < expectedSize) {
m_width = 0;
m_height = 0;
}
}
MemoryOneBitBuffer::~MemoryOneBitBuffer() {
}
bool MemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const {
if (x >= m_width || y >= m_height) {
return false;
}
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8;
return ((static_cast<std::uint8_t>(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01;
}
void MemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) {
if (x >= m_width || y >= m_height) {
return;
}
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8;
if (value) {
m_buffer[byteIndex] = static_cast<std::byte>(static_cast<std::uint8_t>(m_buffer[byteIndex]) | (1u << bitIndex));
} else {
m_buffer[byteIndex] = static_cast<std::byte>(static_cast<std::uint8_t>(m_buffer[byteIndex]) & ~(1u << bitIndex));
}
}
ConstMemoryOneBitBuffer::ConstMemoryOneBitBuffer(std::span<std::byte const> buffer, std::uint16_t width, std::uint16_t height)
: m_width{width}
, m_height{height}
, m_buffer{buffer}
{
std::size_t expectedSize = (m_width * m_height + 8 - 1) / 8;
if (m_buffer.size() < expectedSize) {
m_width = 0;
m_height = 0;
}
}
ConstMemoryOneBitBuffer::~ConstMemoryOneBitBuffer() {
}
bool ConstMemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const {
if (x >= m_width || y >= m_height) {
return false;
}
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8;
return ((static_cast<std::uint8_t>(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01;
}
void ConstMemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) {
std::ignore = x;
std::ignore = y;
std::ignore = value;
}
ClippedImage::ClippedImage(OneBitBufferInterface* underlying, std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height)
: m_underlying{underlying}
, m_x{x}
, m_y{y}
, m_width{width}
, m_height{height}
{
}
ClippedImage::~ClippedImage() {
}
bool ClippedImage::isPixelSet(std::uint16_t x, std::uint16_t y) const {
if (x >= m_width || y >= m_height) {
return false;
}
return m_underlying->isPixelSet(x + m_x, y + m_y);
}
void ClippedImage::setPixel(std::uint16_t x, std::uint16_t y, bool value) {
if (x >= m_width || y >= m_height) {
return;
}
m_underlying->setPixel(x + m_x, y + m_y, value);
}
ImageElement::ImageElement(std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height) ImageElement::ImageElement(std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height)
: m_x{x} : m_x{x}
, m_y{y} , m_y{y}
@ -1038,7 +942,7 @@ ElementType ClippedTextElement::elementType() const {
std::size_t ClippedTextElement::serializeTo(std::span<std::byte> target) const { std::size_t ClippedTextElement::serializeTo(std::span<std::byte> target) const {
std::size_t pos = 0; std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollImage)); pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::ClippedText));
pos = writeU16LE(target, pos, m_x); pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y); pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width); pos = writeU16LE(target, pos, m_width);
@ -1061,13 +965,7 @@ void ClippedTextElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t
} }
fontData = customFonts[fontIndex]->fontData(); fontData = customFonts[fontIndex]->fontData();
} else { } else {
if (m_fontIndex == 0) { fontData = findEmbeddedFont(m_fontIndex);
fontData = findEmbeddedFont("NokiaSmallPlain_tf");
} else if (m_fontIndex == 1) {
fontData = findEmbeddedFont("5x7_mf");
} else {
return;
}
} }
if (fontData.size() < 23) { if (fontData.size() < 23) {
return; return;
@ -1174,7 +1072,7 @@ ElementType HScrollTextElement::elementType() const {
std::size_t HScrollTextElement::serializeTo(std::span<std::byte> target) const { std::size_t HScrollTextElement::serializeTo(std::span<std::byte> target) const {
std::size_t pos = 0; std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollImage)); pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollText));
pos = writeU16LE(target, pos, m_x); pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y); pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width); pos = writeU16LE(target, pos, m_width);
@ -1198,13 +1096,7 @@ void HScrollTextElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t
} }
fontData = customFonts[fontIndex]->fontData(); fontData = customFonts[fontIndex]->fontData();
} else { } else {
if (m_fontIndex == 0) { fontData = findEmbeddedFont(m_fontIndex);
fontData = findEmbeddedFont("NokiaSmallPlain_tf");
} else if (m_fontIndex == 1) {
fontData = findEmbeddedFont("5x7_mf");
} else {
return;
}
} }
if (fontData.size() < 23) { if (fontData.size() < 23) {
return; return;
@ -1395,7 +1287,7 @@ ElementType CurrentTimeElement::elementType() const {
std::size_t CurrentTimeElement::serializeTo(std::span<std::byte> target) const { std::size_t CurrentTimeElement::serializeTo(std::span<std::byte> target) const {
std::size_t pos = 0; std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollImage)); pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::CurrentTime));
pos = writeU16LE(target, pos, m_x); pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y); pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width); pos = writeU16LE(target, pos, m_width);
@ -1417,13 +1309,7 @@ void CurrentTimeElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t
} }
fontData = customFonts[fontIndex]->fontData(); fontData = customFonts[fontIndex]->fontData();
} else { } else {
if (m_fontIndex == 0) { fontData = findEmbeddedFont(m_fontIndex);
fontData = findEmbeddedFont("NokiaSmallPlain_tf");
} else if (m_fontIndex == 1) {
fontData = findEmbeddedFont("5x7_mf");
} else {
return;
}
} }
if (fontData.size() < 23) { if (fontData.size() < 23) {
return; return;
@ -1923,7 +1809,7 @@ std::size_t serializeFile(std::span<std::byte>& buffer, File const& file) {
pos = writeU8LE(buffer, pos, 0xAF); pos = writeU8LE(buffer, pos, 0xAF);
pos = writeU8LE(buffer, pos, 0x7E); pos = writeU8LE(buffer, pos, 0x7E);
pos = writeU8LE(buffer, pos, 0x2B); pos = writeU8LE(buffer, pos, 0x2B);
pos = writeU8LE(buffer, pos, 0x64); pos = writeU8LE(buffer, pos, 0x63);
pos = writeU32LE(buffer, pos, 1); pos = writeU32LE(buffer, pos, 1);
pos = writeU16LE(buffer, pos, file.sections.size()); pos = writeU16LE(buffer, pos, file.sections.size());
pos = writeU16LE(buffer, pos, 0); pos = writeU16LE(buffer, pos, 0);

@ -2,6 +2,7 @@
#define MONOFORMAT_STRUCTURED_HPP #define MONOFORMAT_STRUCTURED_HPP
#include "monoformat_parsehelpers.hpp" #include "monoformat_parsehelpers.hpp"
#include "monoformat_schema.hpp"
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@ -11,12 +12,6 @@
namespace monoformat { namespace monoformat {
enum class SectionType {
AlwaysDrawn = 1,
TimeBasedDrawn = 2,
CustomFont = 32,
};
struct Section { struct Section {
virtual ~Section() = default; virtual ~Section() = default;
virtual SectionType sectionType() const = 0; virtual SectionType sectionType() const = 0;
@ -28,26 +23,6 @@ protected:
class CustomFontSection; class CustomFontSection;
enum class ElementType {
Image = 1,
Animation = 2,
HScrollImage = 3,
VScrollImage = 4,
Line = 5,
ClippedText = 16,
HScrollText = 17,
//VScrollText = 18,
CurrentTime = 32,
};
struct OneBitBufferInterface {
using Color = bool;
virtual ~OneBitBufferInterface() = default;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const = 0;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) = 0;
};
struct Element { struct Element {
virtual ~Element() = default; virtual ~Element() = default;
virtual ElementType elementType() const = 0; virtual ElementType elementType() const = 0;
@ -58,41 +33,6 @@ protected:
Element() = default; Element() = default;
}; };
struct MemoryOneBitBuffer : public OneBitBufferInterface {
MemoryOneBitBuffer(std::span<std::byte> buffer, std::uint16_t width, std::uint16_t height);
virtual ~MemoryOneBitBuffer() override;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const override;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) override;
private:
std::uint16_t m_width{};
std::uint16_t m_height{};
std::span<std::byte> m_buffer;
};
struct ConstMemoryOneBitBuffer : public OneBitBufferInterface {
ConstMemoryOneBitBuffer(std::span<std::byte const> buffer, std::uint16_t width, std::uint16_t height);
virtual ~ConstMemoryOneBitBuffer() override;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const override;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) override;
private:
std::uint16_t m_width{};
std::uint16_t m_height{};
std::span<std::byte const> m_buffer;
};
struct ClippedImage : public OneBitBufferInterface {
ClippedImage(OneBitBufferInterface* underlying, std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height);
virtual ~ClippedImage() override;
virtual bool isPixelSet(std::uint16_t x, std::uint16_t y) const override;
virtual void setPixel(std::uint16_t x, std::uint16_t y, bool value) override;
private:
OneBitBufferInterface* m_underlying{};
std::uint16_t m_x{};
std::uint16_t m_y{};
std::uint16_t m_width{};
std::uint16_t m_height{};
};
struct ImageElement : public Element { struct ImageElement : public Element {
ImageElement(std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height); ImageElement(std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height);
@ -223,10 +163,6 @@ private:
std::vector<std::byte> m_buffer; std::vector<std::byte> m_buffer;
}; };
enum class LineStyle : std::uint8_t {
Solid = 0,
};
struct LineElement : public Element { struct LineElement : public Element {
LineElement(std::uint16_t originX, std::uint16_t originY, std::uint16_t targetX, std::uint16_t targetY, LineStyle lineStyle, std::uint8_t flags); LineElement(std::uint16_t originX, std::uint16_t originY, std::uint16_t targetX, std::uint16_t targetY, LineStyle lineStyle, std::uint8_t flags);

Loading…
Cancel
Save