implement word wrap in text node

This commit is contained in:
2019-09-13 21:36:14 +02:00
parent 53787409cb
commit bbd9dfc4a9
4 changed files with 92 additions and 43 deletions

View File

@@ -72,6 +72,42 @@ void FontManager::change_scale(float scale)
f.second.change_scale(scale);
}
std::vector<TextMesh::Token> TextMesh::tokenize(const std::string& s, const Font& f) const noexcept
{
std::vector<std::string> parts;
std::array<char, 7> delims = { ' ', '\n', ',', '.', ':', '?', '!' };
std::string tmp;
bool wrap = false;
for (char c : s)
{
bool is_delim = std::find(delims.begin(), delims.end(), c) != delims.end();
wrap |= is_delim;
if (wrap && !is_delim)
{
parts.push_back(tmp);
tmp.clear();
wrap = false;
}
tmp.push_back(c);
}
if (!tmp.empty())
parts.push_back(tmp);
std::vector<TextMesh::Token> ret;
for (auto p : parts)
{
float x = 0;
float y = 0;
for (char c : p)
{
stbtt_aligned_quad q;
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c - f.start_char, &x, &y, &q, true);
}
ret.emplace_back(p, x * f.scale);
}
return ret;
}
bool TextMesh::create()
{
App::I->render_task([this]
@@ -98,42 +134,48 @@ void TextMesh::update(kFont id, const char* text)
auto& f = FontManager::get(id);
if (f.chars.size())
{
const auto len = strlen(text);
float x = 0;
float y = 0;
std::vector<glm::vec4> v;
std::vector<GLushort> idx;
glm::vec2 bbmin(FLT_MAX);
glm::vec2 bbmax(-FLT_MAX);
for (int i = 0; i < len; i++)
std::vector<Token> parts = max_width > 0 ?
tokenize(text, f) :
std::vector<Token>{ Token(text, 0.f) };
for (auto p : parts)
{
if (text[i] == '\n')
{
x = 0;
y += f.size * f.scale;
continue;
}
if (max_width > 0 && x > max_width * f.scale /*font scale factor*/)
if (max_width > 0 && x + p.w > max_width * f.scale /*font scale factor*/)
{
x = 0;
y += f.size * f.scale;
}
int c = text[i] - f.start_char;
stbtt_aligned_quad q;
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c, &x, &y, &q, true);
auto n = (int)v.size();
v.emplace_back(q.x0/f.scale, q.y1/f.scale, q.s0, q.t1);
v.emplace_back(q.x0/f.scale, q.y0/f.scale, q.s0, q.t0);
v.emplace_back(q.x1/f.scale, q.y0/f.scale, q.s1, q.t0);
v.emplace_back(q.x1/f.scale, q.y1/f.scale, q.s1, q.t1);
idx.push_back(n+0);
idx.push_back(n+1);
idx.push_back(n+2);
idx.push_back(n+0);
idx.push_back(n+2);
idx.push_back(n+3);
bbmin = glm::min(bbmin, { q.x0/f.scale, q.y0/f.scale });
bbmax = glm::max(bbmax, { q.x1/f.scale, q.y1/f.scale });
for (char c : p.s)
{
if (c == '\n')
{
x = 0;
y += f.size * f.scale;
continue;
}
stbtt_aligned_quad q;
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c - f.start_char, &x, &y, &q, true);
auto n = (int)v.size();
v.emplace_back(q.x0 / f.scale, q.y1 / f.scale, q.s0, q.t1);
v.emplace_back(q.x0 / f.scale, q.y0 / f.scale, q.s0, q.t0);
v.emplace_back(q.x1 / f.scale, q.y0 / f.scale, q.s1, q.t0);
v.emplace_back(q.x1 / f.scale, q.y1 / f.scale, q.s1, q.t1);
idx.push_back(n + 0);
idx.push_back(n + 1);
idx.push_back(n + 2);
idx.push_back(n + 0);
idx.push_back(n + 2);
idx.push_back(n + 3);
bbmin = glm::min(bbmin, { q.x0 / f.scale, q.y0 / f.scale });
bbmax = glm::max(bbmax, { q.x1 / f.scale, q.y1 / f.scale });
}
}
for (auto& vi : v)
vi -= glm::vec4(bbmin, 0, 0);