Skip to content

Commit 16cf925

Browse files
feat(core): Added text rendering capabilities
1 parent 89a3ed4 commit 16cf925

8 files changed

Lines changed: 329 additions & 4 deletions

File tree

main/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ idf_component_register(SRCS
55
"src/Utils.cpp"
66
"src/Texture.cpp"
77
"src/Collider.cpp"
8+
"src/Font.cpp"
89
"src/Shapes/Shape.cpp"
910
"src/Shapes/Circle.cpp"
1011
"src/Shapes/Rectangle.cpp"
@@ -19,10 +20,12 @@ idf_component_register(SRCS
1920
"examples/Fire.cpp"
2021
"examples/Platformer.cpp"
2122
"examples/SpaceShooter.cpp"
23+
"examples/TextExample.cpp"
2224
INCLUDE_DIRS
2325
"include"
2426
"include/Shapes"
2527
"include/examples"
28+
"include/Font"
2629
REQUIRES ESP32-HUB75-MatrixPanel-I2S-DMA
2730
PRIV_REQUIRES esp_timer perfmon)
2831

main/examples/TextExample.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "examples/TextExample.hpp"
2+
#include "Font/Font.hpp"
3+
#include "Renderer.hpp"
4+
5+
void runTextExample() {
6+
int width = 64;
7+
int height = 64;
8+
Renderer renderer(width, height);
9+
Font font = defaultFont;
10+
Pixels pixels;
11+
12+
HUB75Display display(width, height);
13+
if (!display.isInitialized()) {
14+
return;
15+
}
16+
17+
display.setBrightness(100);
18+
19+
while (1) {
20+
pixels.clear();
21+
renderer.drawText(pixels, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0, 0, font,
22+
{255, 0, 0, 1.0f}, true);
23+
24+
renderer.drawText(pixels, "abcdefghijklmnopqrstuvwxyz", 0, 24, font,
25+
{0, 255, 0, 1.0f}, true);
26+
renderer.drawText(pixels, "0123456789", 0, 48, font, {0, 0, 255, 1.0f},
27+
true);
28+
29+
display.setBuffer(pixels);
30+
vTaskDelay(pdMS_TO_TICKS(10000));
31+
pixels.clear();
32+
renderer.drawText(pixels, "!\"#$%&'()*+,-./:;<=>?@[\\]^_`|~ ", 0, 0,
33+
font, {255, 255, 0, 1.0f}, true);
34+
display.setBuffer(pixels);
35+
vTaskDelay(pdMS_TO_TICKS(10000));
36+
}
37+
}

main/include/Font/Font.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#pragma once
2+
#include <cstdint>
3+
#include <stdint.h>
4+
#include <string>
5+
#include <vector>
6+
7+
class Font {
8+
public:
9+
struct Glyph {
10+
char character;
11+
uint8_t width;
12+
uint8_t height;
13+
uint8_t x_offset;
14+
const uint8_t *data;
15+
};
16+
17+
static const uint8_t FONT_DATA[];
18+
static const Glyph FONT_TABLE[];
19+
static const size_t FONT_TABLE_SIZE;
20+
21+
Font() = default;
22+
23+
const Glyph *getGlyph(char c) const;
24+
uint8_t getHeight() const { return 7; } // Standard height
25+
uint8_t getCharWidth(char c) const;
26+
uint8_t getCharSpacing(char c) const; // Get spacing after character};
27+
};
28+
extern Font defaultFont;

main/include/Renderer.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include "Font/Font.hpp"
23
#include "Shapes/Collection.hpp"
34
#include "Utils.hpp"
45
#include <algorithm>
@@ -17,7 +18,10 @@ class Renderer {
1718
const Color &backgroundColor = Color(255, 255, 255, 1.0f));
1819

1920
void render(Pixels &pixels, const std::vector<Collection *> &collections,
20-
const DrawOptions &options);
21+
const DrawOptions &options);
22+
23+
void drawText(Pixels &pixels, const std::string &text, int x, int y,
24+
const Font &font, const Color &color, bool wrap = false);
2125

2226
static Pixels blendPixels(const Pixels &pixels);
2327
static Pixel blendPixel(const Pixel &background, const Pixel &foreground);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
void runTextExample();

main/main.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "examples/SolarSystem.hpp"
55
#include "examples/SpaceShooter.hpp"
66
#include "examples/TestShapes.hpp"
7+
#include "examples/TextExample.hpp"
78

89
extern "C" int app_main(void) {
910
// To run an example, uncomment it and comment out the others
@@ -12,6 +13,7 @@ extern "C" int app_main(void) {
1213
// runCollisionTest();
1314
// runFire();
1415
// runPlatformer();
15-
runSpaceShooter();
16+
// runSpaceShooter();
17+
runTextExample();
1618
return 0;
1719
}

main/src/Font.cpp

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#include "Font.hpp"
2+
3+
// Font data with proper widths for each character
4+
const uint8_t Font::FONT_DATA[] = {
5+
// Numbers (width: 5)
6+
0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E, // '0'
7+
0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E, // '1'
8+
0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F, // '2'
9+
0x0E, 0x11, 0x01, 0x06, 0x01, 0x11, 0x0E, // '3'
10+
0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02, // '4'
11+
0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E, // '5'
12+
0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E, // '6'
13+
0x1F, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, // '7'
14+
0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E, // '8'
15+
0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C, // '9'
16+
17+
// Uppercase Letters (most width: 5, some narrower)
18+
0x04, 0x0A, 0x11, 0x11, 0x1F, 0x11, 0x11, // 'A' (5)
19+
0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E, // 'B' (5)
20+
0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E, // 'C' (5)
21+
0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E, // 'D' (5)
22+
0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F, // 'E' (5)
23+
0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10, // 'F' (5)
24+
0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F, // 'G' (5)
25+
0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11, // 'H' (5)
26+
0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E, // 'I' (3)
27+
0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C, // 'J' (4)
28+
0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11, // 'K' (5)
29+
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F, // 'L' (5)
30+
0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11, // 'M' (5)
31+
0x11, 0x19, 0x19, 0x15, 0x13, 0x13, 0x11, // 'N' (5)
32+
0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E, // 'O' (5)
33+
0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10, // 'P' (5)
34+
0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D, // 'Q' (5)
35+
0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11, // 'R' (5)
36+
0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E, // 'S' (5)
37+
0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, // 'T' (5)
38+
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E, // 'U' (5)
39+
0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04, // 'V' (5)
40+
0x11, 0x11, 0x11, 0x15, 0x15, 0x1B, 0x11, // 'W' (5)
41+
0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11, // 'X' (5)
42+
0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04, // 'Y' (5)
43+
0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F, // 'Z' (5)
44+
45+
// Lowercase Letters (variable widths)
46+
0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F, // 'a' (4)
47+
0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x1E, // 'b' (4)
48+
0x00, 0x00, 0x0E, 0x10, 0x10, 0x11, 0x0E, // 'c' (4)
49+
0x01, 0x01, 0x0D, 0x13, 0x11, 0x11, 0x0F, // 'd' (4)
50+
0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E, // 'e' (4)
51+
0x06, 0x09, 0x08, 0x1C, 0x08, 0x08, 0x08, // 'f' (3)
52+
0x00, 0x0F, 0x11, 0x11, 0x0F, 0x01, 0x0E, // 'g' (4)
53+
0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11, // 'h' (4)
54+
0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x0E, // 'i' (1)
55+
0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0C, // 'j' (2)
56+
0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12, // 'k' (4)
57+
0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E, // 'l' (1)
58+
0x00, 0x00, 0x1A, 0x15, 0x15, 0x15, 0x15, // 'm' (5)
59+
0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11, // 'n' (4)
60+
0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E, // 'o' (4)
61+
0x00, 0x00, 0x1E, 0x11, 0x1E, 0x10, 0x10, // 'p' (4)
62+
0x00, 0x00, 0x0D, 0x13, 0x0F, 0x01, 0x01, // 'q' (4)
63+
0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10, // 'r' (4)
64+
0x00, 0x00, 0x0E, 0x10, 0x0E, 0x01, 0x1E, // 's' (4)
65+
0x08, 0x08, 0x1C, 0x08, 0x08, 0x09, 0x06, // 't' (3)
66+
0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0D, // 'u' (4)
67+
0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04, // 'v' (5)
68+
0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A, // 'w' (5)
69+
0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11, // 'x' (5)
70+
0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E, // 'y' (4)
71+
0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F, // 'z' (4)
72+
73+
/// Basic Symbols
74+
0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, // '!' (1)
75+
0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, // '"' (3)
76+
0x00, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x00, // '#' (5)
77+
0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04, // '$' (5)
78+
0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03, // '%' (5)
79+
0x0C, 0x12, 0x14, 0x08, 0x15, 0x12, 0x0D, // '&' (5)
80+
0x0C, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, // '\'' (1)
81+
0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02, // '(' (3)
82+
0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, // ')' (3)
83+
0x00, 0x04, 0x15, 0x0E, 0x15, 0x04, 0x00, // '*' (5)
84+
0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, // '+' (5)
85+
0x00, 0x00, 0x00, 0x00, 0x0C, 0x04, 0x08, // ',' (1)
86+
0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, // '-' (5)
87+
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, // '.' (1)
88+
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, // '/' (5)
89+
0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, // ':' (1)
90+
0x18, 0x18, 0x00, 0x00, 0x18, 0x08, 0x10, // ';' (1)
91+
0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, // '<' (5)
92+
0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, // '=' (5)
93+
0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, // '>' (5)
94+
0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04, // '?' (5)
95+
0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0E, // '@' (5)
96+
0x1F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1F, // '[' (3)
97+
0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x01, // '\' (5)
98+
0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, // ']' (3)
99+
0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00, // '^' (5)
100+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, // '_' (5)
101+
0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, // '`' (2)
102+
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, // '|' (1)
103+
0x00, 0x00, 0x1D, 0x17, 0x00, 0x00, 0x00, // '~' (5)
104+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ' ' (space) (3)
105+
};
106+
107+
const Font::Glyph Font::FONT_TABLE[] = {
108+
// Numbers (width: 5)
109+
{'0', 5, 7, 0, &FONT_DATA[0]}, {'1', 3, 7, 1, &FONT_DATA[7]},
110+
{'2', 5, 7, 0, &FONT_DATA[14]}, {'3', 5, 7, 0, &FONT_DATA[21]},
111+
{'4', 5, 7, 0, &FONT_DATA[28]}, {'5', 5, 7, 0, &FONT_DATA[35]},
112+
{'6', 5, 7, 0, &FONT_DATA[42]}, {'7', 5, 7, 0, &FONT_DATA[49]},
113+
{'8', 5, 7, 0, &FONT_DATA[56]}, {'9', 5, 7, 0, &FONT_DATA[63]},
114+
115+
// Uppercase
116+
{'A', 5, 7, 0, &FONT_DATA[70]}, {'B', 5, 7, 0, &FONT_DATA[77]},
117+
{'C', 5, 7, 0, &FONT_DATA[84]}, {'D', 5, 7, 0, &FONT_DATA[91]},
118+
{'E', 5, 7, 0, &FONT_DATA[98]}, {'F', 5, 7, 0, &FONT_DATA[105]},
119+
{'G', 5, 7, 0, &FONT_DATA[112]}, {'H', 5, 7, 0, &FONT_DATA[119]},
120+
{'I', 3, 7, 1, &FONT_DATA[126]}, {'J', 4, 7, 0, &FONT_DATA[133]},
121+
{'K', 5, 7, 0, &FONT_DATA[140]}, {'L', 5, 7, 0, &FONT_DATA[147]},
122+
{'M', 5, 7, 0, &FONT_DATA[154]}, {'N', 5, 7, 0, &FONT_DATA[161]},
123+
{'O', 5, 7, 0, &FONT_DATA[168]}, {'P', 5, 7, 0, &FONT_DATA[175]},
124+
{'Q', 5, 7, 0, &FONT_DATA[182]}, {'R', 5, 7, 0, &FONT_DATA[189]},
125+
{'S', 5, 7, 0, &FONT_DATA[196]}, {'T', 5, 7, 0, &FONT_DATA[203]},
126+
{'U', 5, 7, 0, &FONT_DATA[210]}, {'V', 5, 7, 0, &FONT_DATA[217]},
127+
{'W', 5, 7, 0, &FONT_DATA[224]}, {'X', 5, 7, 0, &FONT_DATA[231]},
128+
{'Y', 5, 7, 0, &FONT_DATA[238]}, {'Z', 5, 7, 0, &FONT_DATA[245]},
129+
130+
// Lowercase
131+
{'a', 5, 7, 0, &FONT_DATA[252]}, {'b', 5, 7, 0, &FONT_DATA[259]},
132+
{'c', 4, 7, 0, &FONT_DATA[266]}, {'d', 5, 7, 0, &FONT_DATA[273]},
133+
{'e', 5, 7, 0, &FONT_DATA[280]}, {'f', 3, 7, 0, &FONT_DATA[287]},
134+
{'g', 5, 7, 0, &FONT_DATA[294]}, {'h', 5, 7, 0, &FONT_DATA[301]},
135+
{'i', 3, 7, 1, &FONT_DATA[308]}, {'j', 2, 7, 2, &FONT_DATA[315]},
136+
{'k', 4, 7, 0, &FONT_DATA[322]}, {'l', 3, 7, 1, &FONT_DATA[329]},
137+
{'m', 5, 7, 0, &FONT_DATA[336]}, {'n', 5, 7, 0, &FONT_DATA[343]},
138+
{'o', 5, 7, 0, &FONT_DATA[350]}, {'p', 5, 7, 0, &FONT_DATA[357]},
139+
{'q', 5, 7, 0, &FONT_DATA[364]}, {'r', 4, 7, 0, &FONT_DATA[371]},
140+
{'s', 5, 7, 0, &FONT_DATA[378]}, {'t', 3, 7, 0, &FONT_DATA[385]},
141+
{'u', 5, 7, 0, &FONT_DATA[392]}, {'v', 5, 7, 0, &FONT_DATA[399]},
142+
{'w', 5, 7, 0, &FONT_DATA[406]}, {'x', 5, 7, 0, &FONT_DATA[413]},
143+
{'y', 5, 7, 0, &FONT_DATA[420]}, {'z', 4, 7, 0, &FONT_DATA[427]},
144+
145+
// Symbols
146+
{'!', 1, 7, 2, &FONT_DATA[434]}, {'"', 3, 7, 1, &FONT_DATA[441]},
147+
{'#', 5, 7, 0, &FONT_DATA[448]}, {'$', 5, 7, 0, &FONT_DATA[455]},
148+
{'%', 5, 7, 0, &FONT_DATA[462]}, {'&', 5, 7, 0, &FONT_DATA[469]},
149+
{'\'', 1, 7, 2, &FONT_DATA[476]}, {'(', 3, 7, 1, &FONT_DATA[483]},
150+
{')', 3, 7, 1, &FONT_DATA[490]}, {'*', 5, 7, 0, &FONT_DATA[497]},
151+
{'+', 5, 7, 0, &FONT_DATA[504]}, {',', 1, 7, 2, &FONT_DATA[511]},
152+
{'-', 5, 7, 0, &FONT_DATA[518]}, {'.', 1, 7, 2, &FONT_DATA[525]},
153+
{'/', 5, 7, 0, &FONT_DATA[532]}, {':', 2, 7, 0, &FONT_DATA[539]},
154+
{';', 2, 7, 0, &FONT_DATA[546]}, {'<', 5, 7, 0, &FONT_DATA[553]},
155+
{'=', 5, 7, 0, &FONT_DATA[560]}, {'>', 5, 7, 0, &FONT_DATA[567]},
156+
{'?', 5, 7, 0, &FONT_DATA[574]}, {'@', 5, 7, 0, &FONT_DATA[581]},
157+
{'[', 3, 7, 1, &FONT_DATA[588]}, {'\\', 5, 7, 0, &FONT_DATA[595]},
158+
{']', 3, 7, 0, &FONT_DATA[602]}, {'^', 5, 7, 0, &FONT_DATA[609]},
159+
{'_', 5, 7, 0, &FONT_DATA[616]}, {'`', 2, 7, 1, &FONT_DATA[623]},
160+
{'|', 1, 7, 2, &FONT_DATA[630]}, {'~', 5, 7, 0, &FONT_DATA[637]},
161+
{' ', 3, 7, 1, &FONT_DATA[644]},
162+
};
163+
164+
const size_t Font::FONT_TABLE_SIZE = sizeof(FONT_TABLE) / sizeof(FONT_TABLE[0]);
165+
166+
const Font::Glyph* Font::getGlyph(char c) const {
167+
for (size_t i = 0; i < FONT_TABLE_SIZE; i++) {
168+
if (FONT_TABLE[i].character == c) {
169+
return &FONT_TABLE[i];
170+
}
171+
}
172+
return nullptr;
173+
}
174+
175+
uint8_t Font::getCharWidth(char c) const {
176+
const Glyph* glyph = getGlyph(c);
177+
return glyph ? glyph->width : 4; // Default width for unknown chars
178+
}
179+
180+
uint8_t Font::getCharSpacing(char c) const {
181+
const Glyph* glyph = getGlyph(c);
182+
if (!glyph) return 1;
183+
184+
// Add less spacing after narrow characters
185+
switch(glyph->width) {
186+
case 1: return 2; // Very narrow chars get more spacing
187+
case 2: return 2;
188+
case 3: return 1;
189+
default: return 1; // Normal spacing for wider chars
190+
}
191+
}
192+
193+
Font defaultFont;

main/src/Renderer.cpp

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ Renderer::Renderer(int width, int height, const Color &backgroundColor)
55
: width(width), height(height), backgroundColor(backgroundColor) {}
66

77
void Renderer::render(Pixels &pixels,
8-
const std::vector<Collection *> &collections,
9-
const DrawOptions &options) {
8+
const std::vector<Collection *> &collections,
9+
const DrawOptions &options) {
1010
pixels.reserve(10000);
1111
std::vector<Collection *> sortedCollections = collections;
1212
std::sort(
@@ -17,3 +17,58 @@ void Renderer::render(Pixels &pixels,
1717
PROFILE_FUNC(collection->draw(pixels, options));
1818
}
1919
}
20+
21+
void Renderer::drawText(Pixels &pixels, const std::string &text, int x, int y,
22+
const Font &font, const Color &color, bool wrap) {
23+
int currentX = x;
24+
int currentY = y;
25+
int lineHeight = font.getHeight() + 1;
26+
27+
for (char c : text) {
28+
if (c == '\n') {
29+
currentX = x;
30+
currentY += lineHeight;
31+
continue;
32+
}
33+
34+
const Font::Glyph *glyph = font.getGlyph(c);
35+
36+
if (wrap && currentX > x) {
37+
int charWidth = glyph ? (glyph->width + font.getCharSpacing(c)) : 5;
38+
if (currentX + charWidth > width) {
39+
currentX = x;
40+
currentY += lineHeight;
41+
}
42+
}
43+
44+
if (!glyph) {
45+
for (int i = 0; i < 5; ++i) {
46+
pixels.push_back({currentX + i, currentY, color});
47+
}
48+
for (int i = 0; i < 5; ++i) {
49+
pixels.push_back({currentX + i, currentY + 6, color});
50+
}
51+
for (int i = 0; i < 7; ++i) {
52+
pixels.push_back({currentX, currentY + i, color});
53+
}
54+
for (int i = 0; i < 7; ++i) {
55+
pixels.push_back({currentX + 4, currentY + i, color});
56+
}
57+
currentX += 5;
58+
continue;
59+
}
60+
61+
for (int row = 0; row < glyph->height; ++row) {
62+
uint8_t line = glyph->data[row];
63+
64+
for (int col = 0; col < glyph->width; ++col) {
65+
int bit_pos = 4 - (col + glyph->x_offset);
66+
if (bit_pos >= 0 && (line & (1 << bit_pos))) {
67+
pixels.push_back({currentX + col, currentY + row, color});
68+
}
69+
}
70+
}
71+
72+
currentX += glyph->width + font.getCharSpacing(c);
73+
}
74+
}

0 commit comments

Comments
 (0)