FastLED 3.9.15
Loading...
Searching...
No Matches
truetype.cpp.hpp
Go to the documentation of this file.
1#pragma once
2
3// TrueType Font Implementation for FastLED
4// This file contains the implementation of fl::Font and fl::FontRenderer
5// Include this file ONCE in exactly one .cpp file in your project
6
7#include "fl/font/truetype.h"
8#include "fl/font/ttf_covenant5x5.h" // Embedded default font declarations
9// IWYU pragma: begin_keep
11#include "fl/stl/noexcept.h"
12// IWYU pragma: end_keep // declarations only
13
14namespace fl {
15
16// FontImpl - concrete implementation of Font using stb_truetype
17class FontImpl : public Font {
18public:
19 FontImpl(fl::span<const u8> fontData, i32 fontIndex = 0)
20 : mFontData(fontData.begin(), fontData.end()) {
22 &mFontInfo,
23 mFontData.data(),
25 ) != 0;
26 }
27
28 ~FontImpl() FL_NOEXCEPT override = default;
29
30 bool isValid() const { return mValid; }
31
32 i32 getNumFonts() const override {
34 }
35
36 FontMetrics getMetrics() const override {
37 FontMetrics metrics = {};
38 if (!mValid) return metrics;
39
41 &mFontInfo,
42 &metrics.ascent,
43 &metrics.descent,
44 &metrics.lineGap
45 );
47 &mFontInfo,
48 &metrics.x0, &metrics.y0,
49 &metrics.x1, &metrics.y1
50 );
51 return metrics;
52 }
53
54 float getScaleForPixelHeight(float pixelHeight) const override {
55 if (!mValid) return 0.0f;
57 }
58
59 GlyphMetrics getGlyphMetrics(i32 codepoint) const override {
60 GlyphMetrics metrics = {};
61 if (!mValid) return metrics;
62
64 &mFontInfo, codepoint,
65 &metrics.advanceWidth,
66 &metrics.leftSideBearing
67 );
68
70 &mFontInfo, codepoint,
71 &metrics.x0, &metrics.y0,
72 &metrics.x1, &metrics.y1
73 );
74 metrics.isEmpty = (result == 0);
75
76 return metrics;
77 }
78
79 i32 getKerning(i32 codepoint1, i32 codepoint2) const override {
80 if (!mValid) return 0;
82 }
83
84 GlyphBitmap renderGlyph(i32 codepoint, float scale) const override {
85 return renderGlyph(codepoint, scale, 1, 1);
86 }
87
88 GlyphBitmap renderGlyph(i32 codepoint, float scale,
89 i32 oversampleX, i32 oversampleY) const override {
91 if (!mValid) return result;
92
93 if (oversampleX <= 1 && oversampleY <= 1) {
94 // Simple rendering without oversampling
96 &mFontInfo, scale, scale, codepoint,
97 &result.width, &result.height,
98 &result.xOffset, &result.yOffset
99 );
100
101 if (bitmap && result.width > 0 && result.height > 0) {
102 size_t size = static_cast<size_t>(result.width) * static_cast<size_t>(result.height);
103 result.data.resize(size);
104 for (size_t i = 0; i < size; ++i) {
105 result.data[i] = bitmap[i];
106 }
108 }
109 } else {
110 // Rendering with oversampling for smoother antialiasing
112 &mFontInfo,
113 scale * static_cast<float>(oversampleX),
114 scale * static_cast<float>(oversampleY),
115 0.0f, 0.0f,
116 codepoint,
117 &result.width, &result.height,
118 &result.xOffset, &result.yOffset
119 );
120
121 if (bitmap && result.width > 0 && result.height > 0) {
122 // Downsample to final size
123 i32 finalWidth = (result.width + oversampleX - 1) / oversampleX;
124 i32 finalHeight = (result.height + oversampleY - 1) / oversampleY;
125
126 result.data.resize(
127 static_cast<size_t>(finalWidth) * static_cast<size_t>(finalHeight)
128 );
129
130 for (i32 y = 0; y < finalHeight; ++y) {
131 for (i32 x = 0; x < finalWidth; ++x) {
132 i32 sum = 0;
133 i32 count = 0;
134
135 for (i32 oy = 0; oy < oversampleY; ++oy) {
136 i32 srcY = y * oversampleY + oy;
137 if (srcY >= result.height) break;
138
139 for (i32 ox = 0; ox < oversampleX; ++ox) {
140 i32 srcX = x * oversampleX + ox;
141 if (srcX >= result.width) break;
142
143 sum += bitmap[srcY * result.width + srcX];
144 ++count;
145 }
146 }
147
148 result.data[y * finalWidth + x] = static_cast<u8>(
149 count > 0 ? sum / count : 0
150 );
151 }
152 }
153
154 result.width = finalWidth;
155 result.height = finalHeight;
156 result.xOffset = result.xOffset / oversampleX;
157 result.yOffset = result.yOffset / oversampleY;
158
160 }
161 }
162
163 return result;
164 }
165
167
168private:
171 bool mValid;
172};
173
174// Font static factory methods
178
180 return load(fontData, 0);
181}
182
184 auto impl = fl::make_shared<FontImpl>(fontData, fontIndex);
185 if (!impl->isValid()) {
186 return nullptr;
187 }
188 return impl;
189}
190
191// FontRenderer implementation
193 : mFont(font)
195 , mScale(font ? font->getScaleForPixelHeight(pixelHeight) : 0.0f) {
196}
197
199
202 if (!mFont) return result;
203
204 FontMetrics metrics = mFont->getMetrics();
205 result.ascent = static_cast<float>(metrics.ascent) * mScale;
206 result.descent = static_cast<float>(metrics.descent) * mScale;
207 result.lineGap = static_cast<float>(metrics.lineGap) * mScale;
208 return result;
209}
210
211GlyphBitmap FontRenderer::render(i32 codepoint) const {
212 // Use 2x2 oversampling by default for LED displays
213 return render(codepoint, 2, 2);
214}
215
216GlyphBitmap FontRenderer::render(i32 codepoint, i32 oversampleX, i32 oversampleY) const {
217 if (!mFont) return GlyphBitmap();
218 return mFont->renderGlyph(codepoint, mScale, oversampleX, oversampleY);
219}
220
222 return render(codepoint, 1, 1);
223}
224
225float FontRenderer::getAdvance(i32 codepoint) const {
226 if (!mFont) return 0.0f;
227 GlyphMetrics metrics = mFont->getGlyphMetrics(codepoint);
228 return static_cast<float>(metrics.advanceWidth) * mScale;
229}
230
231float FontRenderer::getKerning(i32 codepoint1, i32 codepoint2) const {
232 if (!mFont) return 0.0f;
233 return static_cast<float>(mFont->getKerning(codepoint1, codepoint2)) * mScale;
234}
235
236float FontRenderer::measureString(const char* str) const {
237 if (!str || !mFont) return 0.0f;
238 return measureString(fl::span<const char>(str, strlen(str)));
239}
240
242 if (str.empty() || !mFont) return 0.0f;
243
244 float width = 0.0f;
245 i32 prevCodepoint = 0;
246
247 for (size_t i = 0; i < str.size(); ++i) {
248 i32 codepoint = static_cast<i32>(static_cast<unsigned char>(str[i]));
249
250 // Add kerning adjustment if this isn't the first character
251 if (prevCodepoint != 0) {
252 width += getKerning(prevCodepoint, codepoint);
253 }
254
255 // Add character advance
256 width += getAdvance(codepoint);
257 prevCodepoint = codepoint;
258 }
259
260 return width;
261}
262
263} // namespace fl
fl::UISlider scale("Scale", 4,.1, 4,.1)
Font() FL_NOEXCEPT=default
static fl::shared_ptr< Font > load(fl::span< const u8 > fontData)
static fl::shared_ptr< Font > loadDefault()
i32 getNumFonts() const override
bool isValid() const
~FontImpl() FL_NOEXCEPT override=default
i32 getKerning(i32 codepoint1, i32 codepoint2) const override
GlyphBitmap renderGlyph(i32 codepoint, float scale, i32 oversampleX, i32 oversampleY) const override
float getScaleForPixelHeight(float pixelHeight) const override
third_party::truetype::stbtt_fontinfo mFontInfo
fl::vector< u8 > mFontData
const third_party::truetype::stbtt_fontinfo & getFontInfo() const
GlyphMetrics getGlyphMetrics(i32 codepoint) const override
GlyphBitmap renderGlyph(i32 codepoint, float scale) const override
FontMetrics getMetrics() const override
FontImpl(fl::span< const u8 > fontData, i32 fontIndex=0)
GlyphBitmap render(i32 codepoint) const
float measureString(const char *str) const
FontRenderer(FontPtr font, float pixelHeight)
~FontRenderer() FL_NOEXCEPT
float getKerning(i32 codepoint1, i32 codepoint2) const
float pixelHeight() const
Definition truetype.h:143
GlyphBitmap renderNoAA(i32 codepoint) const
float getAdvance(i32 codepoint) const
ScaledMetrics getScaledMetrics() const
constexpr bool empty() const FL_NOEXCEPT
Definition span.h:510
constexpr fl::size size() const FL_NOEXCEPT
Definition span.h:458
void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int32_t codepoint, int32_t *advanceWidth, int32_t *leftSideBearing) FL_NOEXCEPT
int32_t stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int32_t ch1, int32_t ch2) FL_NOEXCEPT
float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels) FL_NOEXCEPT
void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int32_t *x0, int32_t *y0, int32_t *x1, int32_t *y1) FL_NOEXCEPT
unsigned char * stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int32_t codepoint, int32_t *width, int32_t *height, int32_t *xoff, int32_t *yoff) FL_NOEXCEPT
void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int32_t *ascent, int32_t *descent, int32_t *lineGap) FL_NOEXCEPT
void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) FL_NOEXCEPT
unsigned char * stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int32_t codepoint, int32_t *width, int32_t *height, int32_t *xoff, int32_t *yoff) FL_NOEXCEPT
int32_t stbtt_GetNumberOfFonts(const unsigned char *data) FL_NOEXCEPT
int32_t stbtt_GetCodepointBox(const stbtt_fontinfo *info, int32_t codepoint, int32_t *x0, int32_t *y0, int32_t *x1, int32_t *y1) FL_NOEXCEPT
int32_t stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int32_t offset) FL_NOEXCEPT
int32_t stbtt_GetFontOffsetForIndex(const unsigned char *data, int32_t index) FL_NOEXCEPT
fl::span< const u8 > covenant5x5()
fl::shared_ptr< Font > FontPtr
Definition truetype.h:129
unsigned char u8
Definition stdint.h:131
constexpr T * begin(T(&array)[N]) FL_NOEXCEPT
size_t strlen(const char *s) FL_NOEXCEPT
constexpr T * end(T(&array)[N]) FL_NOEXCEPT
u8 width
Definition blur.h:186
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
Definition shared_ptr.h:414
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT