MatrixDisplay2025/src/Display.h

245 lines
5.0 KiB
C++

#ifndef DISPLAY_H
#define DISPLAY_H
#include <Adafruit_NeoPixel.h>
enum Align {
ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT
};
enum Font {
FONT5, FONT7
};
struct Color {
uint8_t r, g, b;
};
extern Color WHITE;
extern Color BLACK;
extern Color RED;
extern Color GREEN;
extern Color BLUE;
extern Color YELLOW;
extern Color CYAN;
extern Color MAGENTA;
extern Color ORANGE;
extern Color GREY;
extern const bool DOT7[][7][1];
extern const bool SPECIAL7[][7][3];
extern const bool NUM7[][7][4];
extern const bool ALPHA7[][7][4];
class Display {
Adafruit_NeoPixel leds;
bool pixels[8 * 32]{};
static int mapPixel(const int x, const int y) {
return y * 32 + (y % 2 == 0 ? x : 31 - x);
}
public:
explicit Display(const uint8_t pin): leds(8 * 32, pin,NEO_GRB + NEO_KHZ800) {
//
}
void setBrightness(int i) {
#if LEDS_ENABLED
leds.setBrightness(max(0, min(i, 255)));
#endif
}
void setup() {
#if LEDS_ENABLED
leds.begin();
#endif
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 32; x++) {
pixels[mapPixel(x, y)] = false;
}
}
setBrightness(32);
clear();
show();
}
void show() {
#if LEDS_ENABLED
leds.show();
#endif
}
void setPixel(const int x, const int y, const Color &color) {
const auto index = mapPixel(x, y);
if (index >= 8 * 32) {
Serial.printf("[ERROR] No pixel at (%d, %d) = %d >= %d\n", x, y, index, 8 * 32);
return;
}
#if LEDS_ENABLED
leds.setPixelColor(index, color.r, color.g, color.b);
#endif
pixels[index] = color.r > 0 || color.g > 0 || color.b > 0;
}
void rect(const int x0, const int y0, const int w, const int h, const Color &color) {
for (int y = y0; y < y0 + h; y++) {
for (int x = x0; x < x0 + w; x++) {
setPixel(x, y, color);
}
}
}
void print(int x, const int y, const Align align, const Font font, const Color &color, const char *format, ...) {
char text[32];
va_list args;
va_start(args, format);
vsnprintf(text, sizeof text, format, args);
va_end(args);
const auto width = measure(text, font);
x = align == ALIGN_LEFT ? x : align == ALIGN_RIGHT ? x - width : x - width / 2;
for (const char *c = text; *c; c++) {
x += printChar(x, y, *c, font, color) + 1;
}
}
int printChar(const int x, const int y, const char c, const Font font, const Color &color) {
if (isDot(c)) {
if (c == '.') {
return printSymbol(x, y, 0, color, DOT7);
}
if (c == ',') {
return printSymbol(x, y, 1, color, DOT7);
}
if (c == ':') {
return printSymbol(x, y, 2, color, DOT7);
}
if (c == ';') {
return printSymbol(x, y, 3, color, DOT7);
}
}
if (isSpecial(c)) {
if (c == ' ') {
return printSymbol(x, y, 0, color, SPECIAL7);
}
if (c == '-') {
return printSymbol(x, y, 1, color, SPECIAL7);
}
}
if (isNumber(c)) {
return printSymbol(x, y, c - '0', color, NUM7);
}
if (isLower(c)) {
return printSymbol(x, y, c - 'a', color, ALPHA7);
}
if (isUpper(c)) {
return printSymbol(x, y, c - 'A', color, ALPHA7);
}
Serial.printf("UNKNOWN SYMBOL '%c'\n", c);
return 0;
}
template<int symbolHeight, int symbolWidth>
int printSymbol(const int x, const int y, const int index, const Color &color, const bool symbols[][symbolHeight][symbolWidth]) {
for (int innerY = 0; innerY < symbolHeight; innerY++) {
for (int innerX = 0; innerX < symbolWidth; innerX++) {
if (symbols[index][innerY][innerX]) {
setPixel(x + innerX, y + innerY, color);
}
}
}
return symbolWidth;
}
void clear() {
rect(0, 0, 32, 8, BLACK);
}
void log() const {
Serial.print("+");
for (int x = 0; x < 32; x++) {
Serial.print("--");
}
Serial.print("+\n");
for (int y = 0; y < 8; y++) {
Serial.print("|");
for (int x = 0; x < 32; x++) {
if (pixels[mapPixel(x, y)]) {
Serial.print("##");
} else {
Serial.print(" ");
}
}
Serial.print("|\n");
}
Serial.print("+");
for (int x = 0; x < 32; x++) {
Serial.print("--");
}
Serial.print("+\n");
Serial.print('\n');
}
static uint8_t measure(const char *text, const Font font) {
uint8_t width = 0;
for (const char *c = text; *c; c++) {
if (c != text) {
width++; // space between chars
}
width += getWidth(*c, font);
}
return width;
}
static uint8_t getWidth(const char c, const Font font) {
if (isDot(c)) {
return 1;
}
if (isSpecial(c)) {
return 3;
}
return font == FONT5 ? 3 : 4;
}
static bool isDot(const char c) {
return c == ':' || c == ';' || c == '.' || c == ',';
}
static bool isSpecial(const char c) {
return c == ' ' || c == '-';
}
static bool isNumber(const char c) {
return c >= '0' && c <= '9';
}
static bool isLower(const char c) {
return c >= 'a' && c <= 'z';
}
static bool isUpper(const char c) {
return c >= 'A' && c <= 'Z';
}
};
#endif