Core/StringExt: Add IterateOnCodepoints to remove std::u32string allocations
This commit is contained in:
@@ -381,14 +381,6 @@ namespace Nz
|
||||
if (text.empty())
|
||||
return;
|
||||
|
||||
///TODO: Allow iteration on Unicode characters without allocating any buffer
|
||||
std::u32string characters = ToUtf32String(text);
|
||||
if (characters.empty())
|
||||
{
|
||||
NazaraError("Invalid character set");
|
||||
return;
|
||||
}
|
||||
|
||||
char32_t previousCharacter = 0;
|
||||
|
||||
const Font::SizeInfo& sizeInfo = font.GetSizeInfo(characterSize);
|
||||
@@ -410,85 +402,91 @@ namespace Nz
|
||||
m_lines.back().bounds.height += heightDifference;
|
||||
}
|
||||
|
||||
m_glyphs.reserve(m_glyphs.size() + characters.size() * ((outlineThickness > 0.f) ? 2 : 1));
|
||||
for (char32_t character : characters)
|
||||
IterateOnCodepoints(text, [&](const char32_t* characters, std::size_t characterCount)
|
||||
{
|
||||
if (previousCharacter != 0)
|
||||
m_drawPos.x += font.GetKerning(characterSize, previousCharacter, character);
|
||||
|
||||
previousCharacter = character;
|
||||
|
||||
bool whitespace = true;
|
||||
float advance = characterSpacingOffset;
|
||||
switch (character)
|
||||
for (std::size_t i = 0; i < characterCount; ++i)
|
||||
{
|
||||
case ' ':
|
||||
case '\n':
|
||||
advance += float(sizeInfo.spaceAdvance);
|
||||
break;
|
||||
char32_t character = characters[i];
|
||||
|
||||
case '\t':
|
||||
advance += float(sizeInfo.spaceAdvance) * 4.f;
|
||||
break;
|
||||
if (previousCharacter != 0)
|
||||
m_drawPos.x += font.GetKerning(characterSize, previousCharacter, character);
|
||||
|
||||
default:
|
||||
whitespace = false;
|
||||
break;
|
||||
}
|
||||
previousCharacter = character;
|
||||
|
||||
Glyph glyph;
|
||||
if (!whitespace)
|
||||
{
|
||||
int iAdvance;
|
||||
if (!GenerateGlyph(glyph, character, 0.f, true, font, color, style, lineSpacingOffset, characterSize, 0, &iAdvance))
|
||||
continue; // Glyph failed to load, just skip it (can't do much)
|
||||
|
||||
advance += float(iAdvance);
|
||||
|
||||
if (outlineThickness > 0.f)
|
||||
bool whitespace = true;
|
||||
float advance = characterSpacingOffset;
|
||||
switch (character)
|
||||
{
|
||||
Glyph outlineGlyph;
|
||||
if (GenerateGlyph(outlineGlyph, character, outlineThickness, false, font, outlineColor, style, lineSpacingOffset, characterSize, -1, nullptr))
|
||||
m_glyphs.push_back(outlineGlyph);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldLineWrap(advance))
|
||||
AppendNewLine(font, characterSize, lineSpacingOffset, m_lastSeparatorGlyph, m_lastSeparatorPosition);
|
||||
case ' ':
|
||||
case '\n':
|
||||
advance += float(sizeInfo.spaceAdvance);
|
||||
break;
|
||||
|
||||
glyph.atlas = nullptr;
|
||||
glyph.bounds = Rectf(m_drawPos.x, m_lines.back().bounds.y, advance, lineHeight);
|
||||
case '\t':
|
||||
advance += float(sizeInfo.spaceAdvance) * 4.f;
|
||||
break;
|
||||
|
||||
glyph.corners[0] = glyph.bounds.GetCorner(RectCorner::LeftTop);
|
||||
glyph.corners[1] = glyph.bounds.GetCorner(RectCorner::RightTop);
|
||||
glyph.corners[2] = glyph.bounds.GetCorner(RectCorner::LeftBottom);
|
||||
glyph.corners[3] = glyph.bounds.GetCorner(RectCorner::RightBottom);
|
||||
}
|
||||
|
||||
m_lines.back().bounds.ExtendTo(glyph.bounds);
|
||||
|
||||
switch (character)
|
||||
{
|
||||
case '\n':
|
||||
{
|
||||
AppendNewLine(font, characterSize, lineSpacingOffset);
|
||||
break;
|
||||
default:
|
||||
whitespace = false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
m_drawPos.x += advance;
|
||||
break;
|
||||
Glyph glyph;
|
||||
if (!whitespace)
|
||||
{
|
||||
int iAdvance;
|
||||
if (!GenerateGlyph(glyph, character, 0.f, true, font, color, style, lineSpacingOffset, characterSize, 0, &iAdvance))
|
||||
continue; // Glyph failed to load, just skip it (can't do much)
|
||||
|
||||
advance += float(iAdvance);
|
||||
|
||||
if (outlineThickness > 0.f)
|
||||
{
|
||||
Glyph outlineGlyph;
|
||||
if (GenerateGlyph(outlineGlyph, character, outlineThickness, false, font, outlineColor, style, lineSpacingOffset, characterSize, -1, nullptr))
|
||||
m_glyphs.push_back(outlineGlyph);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldLineWrap(advance))
|
||||
AppendNewLine(font, characterSize, lineSpacingOffset, m_lastSeparatorGlyph, m_lastSeparatorPosition);
|
||||
|
||||
glyph.atlas = nullptr;
|
||||
glyph.bounds = Rectf(m_drawPos.x, m_lines.back().bounds.y, advance, lineHeight);
|
||||
|
||||
glyph.corners[0] = glyph.bounds.GetCorner(RectCorner::LeftTop);
|
||||
glyph.corners[1] = glyph.bounds.GetCorner(RectCorner::RightTop);
|
||||
glyph.corners[2] = glyph.bounds.GetCorner(RectCorner::LeftBottom);
|
||||
glyph.corners[3] = glyph.bounds.GetCorner(RectCorner::RightBottom);
|
||||
}
|
||||
|
||||
m_lines.back().bounds.ExtendTo(glyph.bounds);
|
||||
|
||||
switch (character)
|
||||
{
|
||||
case '\n':
|
||||
{
|
||||
AppendNewLine(font, characterSize, lineSpacingOffset);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
m_drawPos.x += advance;
|
||||
break;
|
||||
}
|
||||
|
||||
if (whitespace)
|
||||
{
|
||||
m_lastSeparatorGlyph = m_glyphs.size();
|
||||
m_lastSeparatorPosition = m_drawPos.x;
|
||||
}
|
||||
|
||||
m_glyphs.push_back(glyph);
|
||||
}
|
||||
|
||||
if (whitespace)
|
||||
{
|
||||
m_lastSeparatorGlyph = m_glyphs.size();
|
||||
m_lastSeparatorPosition = m_drawPos.x;
|
||||
}
|
||||
|
||||
m_glyphs.push_back(glyph);
|
||||
}
|
||||
return true; //< continue iteration
|
||||
});
|
||||
|
||||
m_bounds.ExtendTo(m_lines.back().bounds);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user