-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTextComponent.h
More file actions
325 lines (272 loc) · 9.76 KB
/
Copy pathTextComponent.h
File metadata and controls
325 lines (272 loc) · 9.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "deki-rendering/RendererComponent.h"
#include "BitmapFont.h"
#include "Color.h"
#include "assets/AssetRef.h"
/**
* @brief Text alignment options
*/
enum class TextAlign : uint8_t
{
Left = 0,
Center = 1,
Right = 2
};
/**
* @brief Text vertical alignment options
*
* Top/Middle/Bottom (0-2) are the legacy modes. The additional anchors use
* font-wide typographic metrics so text centers optically regardless of
* whether the string contains ascenders or descenders.
*/
enum class TextVerticalAlign : uint8_t
{
Top = 0,
Middle = 1, // Legacy: centers on visual bounds of the whole font (ascent+descent)
Bottom = 2,
CapCenter = 3, // Centers on cap-height — best for uppercase / mixed UI labels
XCenter = 4, // Centers on x-height — best for lowercase-heavy body text
TypoCenter = 5, // Centers on typographic midline; same as Middle for single-line
Baseline = 6 // Baseline sits on the container center line
};
/**
* @brief Component for rendering text using bitmap fonts
*
* TextComponent renders text strings using BitmapFont for glyph data.
* Supports color tinting, alignment, and word wrapping.
*/
class TextComponent : public RendererComponent
{
public:
DEKI_COMPONENT(TextComponent, RendererComponent, "2D", "5447ea24-d11f-4161-ae10-2f11e0a18d09", "DEKI_FEATURE_TEXT")
DEKI_DESCRIPTION("Draws text with a bitmap font, alignment and word wrap.")
TextComponent();
virtual ~TextComponent();
// ========================================================================
// Editor-visible properties
// ========================================================================
/** @brief Text to display (editor-editable) */
DEKI_EXPORT
std::string text;
/** @brief Font asset reference (GUID stored in editor, auto-loaded) */
DEKI_EXPORT
Deki::AssetRef<BitmapFont> font;
#ifdef DEKI_EDITOR
/** @brief Font size in pixels (maps to baked variant) */
DEKI_EXPORT
DEKI_EDITOR_ONLY
int32_t fontSize = 16;
/** @brief Enable live font preview (editor-only, not serialized) */
bool previewEnabled = false;
/** @brief Font size to preview (editor-only, not serialized) */
int32_t previewSize = 16;
/** @brief True if fontSize is not available as a baked variant (editor-only) */
bool fontSizeUnavailable = false;
#endif
/**
* @brief Set the text to display
* @param text Text string (copied internally)
*/
void SetText(const char* text);
/**
* @brief Set the text to display
* @param text Text string
*/
void SetText(const std::string& text);
/**
* @brief Get the current text
* @return Current text string
*/
const std::string& GetText() const { return text; }
/**
* @brief Font resolve callback for editor integration
*
* Called during RenderContent to let external code (editor) handle font resolution
* (GUID sync, preview, baking). Return non-null to use that font directly,
* or nullptr to fall through to the runtime path (font.Get()).
*/
using FontResolveCallback = BitmapFont*(*)(TextComponent*);
static void SetFontResolveCallback(FontResolveCallback cb);
/**
* @brief Set the font to use for rendering
* @param f Pointer to bitmap font (not owned by TextComponent)
*/
void SetFont(BitmapFont* f);
/**
* @brief Get the current font
* @return Current font or nullptr
*/
BitmapFont* GetFont() { return font.Get(); }
const BitmapFont* GetFont() const { return font.Get(); }
/**
* @brief Set text color
* @param color Text color
*/
void SetColor(const deki::Color& color);
/**
* @brief Set text color (RGB convenience)
* @param r Red (0-255)
* @param g Green (0-255)
* @param b Blue (0-255)
*/
void SetColor(uint8_t r, uint8_t g, uint8_t b);
/**
* @brief Get text color
* @return Current text color
*/
const deki::Color& GetColor() const { return color; }
/**
* @brief Set horizontal text alignment
* @param alignVal Alignment mode
*/
void SetAlign(TextAlign alignVal) { align = alignVal; }
/**
* @brief Get horizontal text alignment
* @return Current alignment
*/
TextAlign GetAlign() const { return align; }
/**
* @brief Set vertical text alignment
* @param alignVal Vertical alignment mode
*/
void SetVerticalAlign(TextVerticalAlign alignVal) { verticalAlign = alignVal; }
/**
* @brief Get vertical text alignment
* @return Current vertical alignment
*/
TextVerticalAlign GetVerticalAlign() const { return verticalAlign; }
/**
* @brief Set text box width
* @param w Width in meters
*/
void SetWidth(float w) { width = w; }
/**
* @brief Get text box width
* @return Width in meters
*/
float GetWidth() const { return width; }
/**
* @brief Set text box height
* @param h Height in meters
*/
void SetHeight(float h) { height = h; }
/**
* @brief Get text box height
* @return Height in meters
*/
float GetHeight() const { return height; }
/**
* @brief Get the measured width of the current text
* @return Width in pixels
*/
int32_t GetTextWidth() const;
/**
* @brief Get the measured height of the current text
* @return Height in pixels (considering line wrapping)
*/
int32_t GetTextHeight() const;
// Clear cached font pointer to force reload (used when fonts are re-baked in editor)
void UnloadAssets() override;
// Unified rendering via QuadBlit
bool RenderContent(const DekiObject* owner,
QuadBlit::Source& outSource,
float& outPivotX,
float& outPivotY,
uint8_t& outTintR,
uint8_t& outTintG,
uint8_t& outTintB,
uint8_t& outTintA) override;
// ========================================================================
// Layout methods (shared between runtime and editor)
// ========================================================================
/**
* @brief Glyph layout info for rendering
*/
struct GlyphLayout
{
const GlyphInfo* glyph; // Glyph data from font
float worldX; // X position relative to component center
float worldY; // Y position relative to component center
};
/**
* @brief Calculate glyph positions for rendering
* @param fontPtr Font to use (can be different from component's font for editor)
* @param outGlyphs Output vector of glyph layouts
*
* Positions are in WORLD coordinates relative to component center.
* Editor multiplies by zoom, runtime uses directly.
*/
void CalculateGlyphLayout(const BitmapFont* fontPtr, std::vector<GlyphLayout>& outGlyphs) const;
/**
* @brief Word-wrap text to fit within maxWidth (public for editor use)
* @param fontPtr Font to use for measurements
* @return Vector of wrapped lines
*/
std::vector<std::string> WrapTextWithFont(const BitmapFont* fontPtr) const;
// ========================================================================
// Editor-visible properties (public for reflection)
// ========================================================================
/** @brief Text box width in meters */
DEKI_EXPORT
DEKI_UNIT(Distance)
float width = 6.25f;
/** @brief Text box height in meters */
DEKI_EXPORT
DEKI_UNIT(Distance)
float height = 1.5f;
/** @brief Text color */
DEKI_EXPORT
deki::Color color;
/**
* @brief Decoration color (outline / shadow).
* Only used when the bound font is v4+ and was baked with a decoration other
* than None. Ignored for plain alpha fonts.
*/
DEKI_EXPORT
deki::Color decorationColor;
/** @brief Pixel scale for bitmap fonts (1x, 2x, 3x nearest-neighbor) */
DEKI_EXPORT
int32_t pixelScale = 1;
/** @brief Horizontal text alignment */
DEKI_EXPORT
TextAlign align = TextAlign::Left;
/** @brief Vertical text alignment (new components default to cap-center for optical centering) */
DEKI_EXPORT
TextVerticalAlign verticalAlign = TextVerticalAlign::CapCenter;
// Invalidate the render cache (call when text/font/color/size changes)
void InvalidateRenderCache();
private:
static FontResolveCallback s_fontResolveCallback;
// Cached render buffer
uint8_t* m_cachedBuffer = nullptr;
size_t m_cachedBufferSize = 0;
std::string m_cachedText;
int32_t m_cachedWidth = 0;
int32_t m_cachedHeight = 0;
deki::Color m_cachedColor;
deki::Color m_cachedDecorationColor;
TextAlign m_cachedAlign = TextAlign::Left;
TextVerticalAlign m_cachedVerticalAlign = TextVerticalAlign::Top;
BitmapFont* m_cachedFont = nullptr;
int32_t m_cachedPixelScale = 1;
// Cached vertical crop bounds (tight Y range of actual glyph content)
int32_t m_cropFirstRow = 0;
int32_t m_cropHeight = 0;
float m_cropPivotY = 0.5f;
// Render a single glyph to the buffer
void RenderGlyph(const GlyphInfo* glyph,
int32_t x,
int32_t y,
uint8_t* render_buffer,
int screen_width,
int screen_height);
// Helper to measure width of a string
int32_t MeasureLineWidth(const char* str, size_t len) const;
// Word-wrap text to fit within maxWidth
std::vector<std::string> WrapText(int32_t maxWidth) const;
};
// Generated property metadata (after class definition for offsetof)
#include "generated/TextComponent.gen.h"