Abfahrtsanzeiger Display Basic Library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
libmonoformat/cpp/clivis/main.cpp

178 lines
6.1 KiB

#include <monoformat_fontreader.hpp>
#include <monoformat_structured.hpp>
#include <monoformat_parseonly.hpp>
#include <sstream>
#include <fstream>
#include <iostream>
#include <vector>
#include <cstdint>
#include <filesystem>
#include <stdexcept>
#include <atomic>
#include <csignal>
#include <thread>
#include <chrono>
using namespace monoformat;
constexpr static std::uint16_t const ScreenWidth = 120;
constexpr static std::uint16_t const ScreenHeight = 60;
static std::atomic<bool> g_ctrlCPressed;
static void handleCtrlC(int) {
g_ctrlCPressed.store(true, std::memory_order_relaxed);
}
template<typename Container>
static Container readEntireFile(std::filesystem::path const& fileName) {
std::ifstream fileReader(fileName, std::ios::binary | std::ios::ate | std::ios::in);
if (!fileReader) {
std::ostringstream buf;
buf << "Could not open \"" << fileName << "\" for reading";
throw std::runtime_error(buf.str());
}
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;
}
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 h = ScreenHeight / 2;
std::ostringstream buf;
buf << "\xE2\x94\x8C";
for (std::uint16_t i = 0; i < w; ++i) {
buf << "\xE2\x94\x80";
}
buf << "\xE2\x94\x90\n";
for (std::uint16_t y = 0; y < h; ++y) {
buf << "\xE2\x94\x82";
for (std::uint16_t x = 0; x < w; ++x) {
bool const pxUpperSet = imageBuffer.isPixelSet(x, 2 * y + 0);
bool const pxLowerSet = imageBuffer.isPixelSet(x, 2 * y + 1);
if (pxUpperSet && pxLowerSet) {
buf << "\xE2\x96\x88";
} else if (pxUpperSet) {
buf << "\xF0\x9F\xAC\x8E";
} else if (pxLowerSet) {
buf << "\xE2\x96\x84";
} else {
buf << " ";
}
}
buf << "\xE2\x94\x82\n";
}
if (ScreenHeight % 1) {
buf << "\xE2\x94\x82";
for (std::uint16_t x = 0; x < w; ++x) {
bool const pxUpperSet = imageBuffer.isPixelSet(x, ScreenHeight - 1);
if (pxUpperSet) {
buf << "\xF0\x9F\xAC\x8E";
} else {
buf << " ";
}
}
buf << "\xE2\x94\x82\n";
}
buf << "\xE2\x94\x94";
for (std::uint16_t i = 0; i < w; ++i) {
buf << "\xE2\x94\x80";
}
buf << "\xE2\x94\x98\n";
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;
}