utility 2026.2.0
A comprehensive C++ utilities library tailored for the development of modern desktop and extended reality (XR) applications.
Loading...
Searching...
No Matches
text.cpp
1/*
2 Copyright (c) 2026 ETIB Corporation
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
24#include <utility/graphic/size.hpp>
25
26#include <cstdint>
27#include <memory>
28#include <vector>
29
30namespace utility::graphic
31{
32 Text::Text(std::shared_ptr<RessourceProvider> ressourceProvider,
33 const PoseF &pose, const Color32Bit &color,
34 const std::string &content, uint32_t fontSize,
35 const std::string &font)
36 : Renderable(pose, color)
37 , logging::Loggable<Text, logging::DefaultLogger>()
38 , _content(content)
39 , _fontPath(font)
40 , _fontSize(fontSize)
41 {
42 _font = ressourceProvider->loadFont(_fontPath);
43 _meshes = { std::make_shared<Mesh>(std::vector<VertexF> {},
44 std::vector<uint32_t> {}) };
45 updateMesh();
46 }
47
48 std::shared_ptr<Mesh> Text::getMesh() const
49 {
50 return _meshes.front();
51 }
52
53 const std::string &Text::getFontFamily(void) const
54 {
55 return _fontPath;
56 }
57
58 const std::string &Text::getContent(void) const
59 {
60 return _content;
61 }
62
63 Text &Text::setContent(const std::string &content)
64 {
65 _content = content;
66 updateMesh();
67 return *this;
68 }
69
70 uint32_t Text::getFontSize(void) const
71 {
72 return _fontSize;
73 }
74
75 Text &Text::setFontSize(uint32_t fontSize)
76 {
77 _fontSize = fontSize;
78
79 updateMesh();
80
81 return *this;
82 }
83
88
89 std::string Text::getMaterialName() const
90 {
91 return this->getFontFamily() + "_" + std::to_string(this->getFontSize()) + "_material";
92 }
93
95 {
96 graphic::SizeF dimensions({ 0.0, 0.0 });
97
98 std::vector<uint32_t> codepoints = utf8ToCodepoints(_content);
99 const math::Vector2F measured =
100 _font->measureText(_fontSize, codepoints);
101
102 dimensions.setWidth(measured[0]);
103 dimensions.setHeight(measured[1]);
104
105 getLogger().debug() << "Calculated text dimensions for content '"
106 << _content << "' with font size " << _fontSize
107 << ": width = " << dimensions.getWidth()
108 << ", height = " << dimensions.getHeight();
109
110 return dimensions;
111 }
112
114 // Protected Methods //
116
118 {
119 _meshes.front() = std::make_shared<Mesh>(std::vector<VertexF> {},
120 std::vector<uint32_t> {});
121
122 // Glyph quads are built in local (object) space: the pose position and
123 // orientation are applied later through the model matrix, so they are
124 // not baked into positions or normals here.
125 const math::Vector3F localNormal { 0.0f, 0.0f, -1.0f };
126
127 uint32_t indexOffset = 0;
128 std::vector<uint32_t> codepoints = utf8ToCodepoints(_content);
129 std::vector<Glyph> glyphs =
130 _font->processCodePoints(_fontSize, codepoints);
131
132 double penX = 0.0;
133 double baseline = std::round(_font->getAscender(_fontSize));
134
135 for (const auto &g: glyphs) {
136 const float xpos =
137 static_cast<float>(std::round(penX + g.bearing[VEC_X]));
138 const float ypos =
139 static_cast<float>(std::round(-baseline + g.bearing[VEC_Y]));
140
141 const float w = g.size[VEC_X];
142 const float h = g.size[VEC_Y];
143
144 VertexF v0(PositionF(xpos, ypos, 0.0f), localNormal,
145 math::Vector2F({ g.uvMin[VEC_X], g.uvMin[VEC_Y] }),
146 _color);
147
148 VertexF v1(PositionF(xpos, ypos - h, 0.0f), localNormal,
149 math::Vector2F({ g.uvMin[VEC_X], g.uvMax[VEC_Y] }),
150 _color);
151
152 VertexF v2(PositionF(xpos + w, ypos - h, 0.0f), localNormal,
153 math::Vector2F({ g.uvMax[VEC_X], g.uvMax[VEC_Y] }),
154 _color);
155
156 VertexF v3(PositionF(xpos + w, ypos, 0.0f), localNormal,
157 math::Vector2F({ g.uvMax[VEC_X], g.uvMin[VEC_Y] }),
158 _color);
159
160 _meshes.front()->addIndex(indexOffset + 0);
161 _meshes.front()->addIndex(indexOffset + 1);
162 _meshes.front()->addIndex(indexOffset + 2);
163
164 _meshes.front()->addIndex(indexOffset + 0);
165 _meshes.front()->addIndex(indexOffset + 2);
166 _meshes.front()->addIndex(indexOffset + 3);
167
168 _meshes.front()->addVertex(v0);
169 _meshes.front()->addVertex(v1);
170 _meshes.front()->addVertex(v2);
171 _meshes.front()->addVertex(v3);
172
173 indexOffset += 4;
174 penX += g.advance;
175 }
176 }
177 std::vector<uint32_t> Text::utf8ToCodepoints(const std::string &str) const
178 {
179 std::vector<uint32_t> codepoints;
180
181 size_t i = 0;
182 while (i < str.size()) {
183 uint8_t c0 = static_cast<uint8_t>(str[i]);
184 uint32_t codepoint = 0;
185 size_t bytes = 0;
186
187 if (c0 < 0x80) {
188 codepoint = c0;
189 bytes = 1;
190 } else if (c0 >= 0xC2 && c0 <= 0xDF) {
191 codepoint = c0 & 0x1F;
192 bytes = 2;
193 } else if (c0 >= 0xE0 && c0 <= 0xEF) {
194 codepoint = c0 & 0x0F;
195 bytes = 3;
196 } else if (c0 >= 0xF0 && c0 <= 0xF4) {
197 codepoint = c0 & 0x07;
198 bytes = 4;
199 } else {
200 ++i;
201 continue;
202 }
203
204 if (i + bytes > str.size()) {
205 break;
206 }
207
208 bool valid = true;
209 for (size_t j = 1; j < bytes; ++j) {
210 uint8_t cc = static_cast<uint8_t>(str[i + j]);
211 if ((cc & 0xC0) != 0x80) {
212 valid = false;
213 break;
214 }
215 codepoint = (codepoint << 6) | (cc & 0x3F);
216 }
217
218 if (valid) {
219 if ((bytes == 2 && codepoint < 0x80)
220 || (bytes == 3
221 && (codepoint < 0x800
222 || (codepoint >= 0xD800 && codepoint <= 0xDFFF)))
223 || (bytes == 4
224 && (codepoint < 0x10000 || codepoint > 0x10FFFF))) {
225 valid = false;
226 }
227 }
228
229 if (valid) {
230 codepoints.push_back(codepoint);
231 i += bytes;
232 } else {
233 ++i;
234 }
235 }
236
237 return codepoints;
238 }
239} // namespace utility::graphic
Position in 3D space represented as a vector of three PositionComponentType components (x,...
Definition position.hpp:53
The Renderable class represents an object that can be rendered in the graphics application.
std::vector< std::shared_ptr< Mesh > > _meshes
Meshes associated with this renderable object.
Color32Bit _color
Text RGBA color.
Storage for text content and rendering properties.
Definition text.hpp:75
std::shared_ptr< Font > _font
Shared pointer to the font used for rendering.
Definition text.hpp:83
codePointString utf8ToCodepoints(const std::string &str) const
Converts a UTF-8 encoded string to a string of Unicode code points.
Definition text.cpp:177
const std::string & getFontFamily(void) const
Get the font family (path) used for rendering the text.
Definition text.cpp:53
void updateMesh(void)
Updates the mesh for rendering the text based on the current content, font, and font size.
Definition text.cpp:117
std::string getMaterialName() const override
Get the material name.
Definition text.cpp:89
const std::string & getContent(void) const
Get the text content.
Definition text.cpp:58
std::shared_ptr< Mesh > getMesh() const
Get the mesh for rendering the text.
Definition text.cpp:48
RenderableType getRenderableType(void) const override
Get the RenderableType of this object.
Definition text.cpp:84
Text & setFontSize(uint32_t fontSize)
Set the font size.
Definition text.cpp:75
uint32_t getFontSize(void) const
Get the font size.
Definition text.cpp:70
Text & setContent(const std::string &content)
Set the text content.
Definition text.cpp:63
graphic::SizeF getTextDimensions(void) const
Get the dimensions of the rendered text.
Definition text.cpp:94
Vertex type containing common mesh attributes.
Definition vertex.hpp:38
LoggerType & getLogger(void)
Get the internal logger.
Definition loggable.hpp:98
3D vector class inheriting from glm::vec3.
Definition vector.hpp:83
Text rendering properties and storage.