implement word wrap in text node
This commit is contained in:
92
src/font.cpp
92
src/font.cpp
@@ -72,6 +72,42 @@ void FontManager::change_scale(float scale)
|
|||||||
f.second.change_scale(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()
|
bool TextMesh::create()
|
||||||
{
|
{
|
||||||
App::I->render_task([this]
|
App::I->render_task([this]
|
||||||
@@ -98,42 +134,48 @@ void TextMesh::update(kFont id, const char* text)
|
|||||||
auto& f = FontManager::get(id);
|
auto& f = FontManager::get(id);
|
||||||
if (f.chars.size())
|
if (f.chars.size())
|
||||||
{
|
{
|
||||||
const auto len = strlen(text);
|
|
||||||
float x = 0;
|
float x = 0;
|
||||||
float y = 0;
|
float y = 0;
|
||||||
std::vector<glm::vec4> v;
|
std::vector<glm::vec4> v;
|
||||||
std::vector<GLushort> idx;
|
std::vector<GLushort> idx;
|
||||||
glm::vec2 bbmin(FLT_MAX);
|
glm::vec2 bbmin(FLT_MAX);
|
||||||
glm::vec2 bbmax(-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')
|
if (max_width > 0 && x + p.w > max_width * f.scale /*font scale factor*/)
|
||||||
{
|
|
||||||
x = 0;
|
|
||||||
y += f.size * f.scale;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (max_width > 0 && x > max_width * f.scale /*font scale factor*/)
|
|
||||||
{
|
{
|
||||||
x = 0;
|
x = 0;
|
||||||
y += f.size * f.scale;
|
y += f.size * f.scale;
|
||||||
}
|
}
|
||||||
int c = text[i] - f.start_char;
|
for (char c : p.s)
|
||||||
stbtt_aligned_quad q;
|
{
|
||||||
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c, &x, &y, &q, true);
|
if (c == '\n')
|
||||||
auto n = (int)v.size();
|
{
|
||||||
v.emplace_back(q.x0/f.scale, q.y1/f.scale, q.s0, q.t1);
|
x = 0;
|
||||||
v.emplace_back(q.x0/f.scale, q.y0/f.scale, q.s0, q.t0);
|
y += f.size * f.scale;
|
||||||
v.emplace_back(q.x1/f.scale, q.y0/f.scale, q.s1, q.t0);
|
continue;
|
||||||
v.emplace_back(q.x1/f.scale, q.y1/f.scale, q.s1, q.t1);
|
}
|
||||||
idx.push_back(n+0);
|
stbtt_aligned_quad q;
|
||||||
idx.push_back(n+1);
|
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c - f.start_char, &x, &y, &q, true);
|
||||||
idx.push_back(n+2);
|
auto n = (int)v.size();
|
||||||
idx.push_back(n+0);
|
v.emplace_back(q.x0 / f.scale, q.y1 / f.scale, q.s0, q.t1);
|
||||||
idx.push_back(n+2);
|
v.emplace_back(q.x0 / f.scale, q.y0 / f.scale, q.s0, q.t0);
|
||||||
idx.push_back(n+3);
|
v.emplace_back(q.x1 / f.scale, q.y0 / f.scale, q.s1, q.t0);
|
||||||
bbmin = glm::min(bbmin, { q.x0/f.scale, q.y0/f.scale });
|
v.emplace_back(q.x1 / f.scale, q.y1 / f.scale, q.s1, q.t1);
|
||||||
bbmax = glm::max(bbmax, { q.x1/f.scale, q.y1/f.scale });
|
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)
|
for (auto& vi : v)
|
||||||
vi -= glm::vec4(bbmin, 0, 0);
|
vi -= glm::vec4(bbmin, 0, 0);
|
||||||
|
|||||||
@@ -44,6 +44,13 @@ public:
|
|||||||
|
|
||||||
class TextMesh
|
class TextMesh
|
||||||
{
|
{
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
float w;
|
||||||
|
Token(const std::string& str, float width) : s(str), w(width) {}
|
||||||
|
};
|
||||||
|
std::vector<Token> tokenize(const std::string& s, const Font& f) const noexcept;
|
||||||
public:
|
public:
|
||||||
GLuint font_array = 0;
|
GLuint font_array = 0;
|
||||||
int font_array_count = 0;
|
int font_array_count = 0;
|
||||||
|
|||||||
17
src/util.cpp
17
src/util.cpp
@@ -544,23 +544,6 @@ glm::vec3 convert_rgb2hsv(const glm::vec3 c)
|
|||||||
return glm::vec3(fabs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
return glm::vec3(fabs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> split(const std::string& subject, char d, int max_split/* = 0*/)
|
|
||||||
{
|
|
||||||
std::vector<std::string> ret;
|
|
||||||
size_t start = 0;
|
|
||||||
size_t n = subject.find_first_of(d);
|
|
||||||
while (n != std::string::npos)
|
|
||||||
{
|
|
||||||
ret.push_back(subject.substr(start, n - start));
|
|
||||||
start = n + 1;
|
|
||||||
if (max_split && ret.size() == max_split)
|
|
||||||
break;
|
|
||||||
n = subject.find_first_of(d, start);
|
|
||||||
}
|
|
||||||
ret.push_back(subject.substr(start));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string unescape(const std::string& s)
|
std::string unescape(const std::string& s)
|
||||||
{
|
{
|
||||||
std::string res;
|
std::string res;
|
||||||
|
|||||||
19
src/util.h
19
src/util.h
@@ -45,6 +45,24 @@ std::vector<T> poly_remove_duplicate(const std::vector<T>& v, const float toller
|
|||||||
template<>
|
template<>
|
||||||
std::vector<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t>& v, const float tollerance);
|
std::vector<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t>& v, const float tollerance);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::vector<std::string> split(const std::string& subject, T d, int max_split = 0)
|
||||||
|
{
|
||||||
|
std::vector<std::string> ret;
|
||||||
|
size_t start = 0;
|
||||||
|
size_t n = subject.find_first_of(d);
|
||||||
|
while (n != std::string::npos)
|
||||||
|
{
|
||||||
|
ret.push_back(subject.substr(start, n - start));
|
||||||
|
start = n + 1;
|
||||||
|
if (max_split && ret.size() == max_split)
|
||||||
|
break;
|
||||||
|
n = subject.find_first_of(d, start);
|
||||||
|
}
|
||||||
|
ret.push_back(subject.substr(start));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// from {origin, size} to {min, max}
|
// from {origin, size} to {min, max}
|
||||||
glm::vec4 rect_to_box(const glm::vec4& rect);
|
glm::vec4 rect_to_box(const glm::vec4& rect);
|
||||||
// from {min, max} to {origin, size}
|
// from {min, max} to {origin, size}
|
||||||
@@ -88,7 +106,6 @@ uint32_t convert_rgb_long(glm::vec3 rgb);
|
|||||||
glm::vec3 convert_hsv2rgb(const glm::vec3 c);
|
glm::vec3 convert_hsv2rgb(const glm::vec3 c);
|
||||||
glm::vec3 convert_rgb2hsv(const glm::vec3 c);
|
glm::vec3 convert_rgb2hsv(const glm::vec3 c);
|
||||||
|
|
||||||
std::vector<std::string> split(const std::string& subject, char d, int max_split = 0);
|
|
||||||
std::string unescape(const std::string& s);
|
std::string unescape(const std::string& s);
|
||||||
std::wstring str2wstr(const std::string& str);
|
std::wstring str2wstr(const std::string& str);
|
||||||
std::string wstr2str(const std::wstring& wstr);
|
std::string wstr2str(const std::wstring& wstr);
|
||||||
|
|||||||
Reference in New Issue
Block a user