Clean up BitmapFont code (#1129)

This commit is contained in:
vfjpl 2021-03-30 17:03:02 +02:00 committed by GitHub
parent 4edb1eb3ad
commit 4d055913dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 70 deletions

View File

@ -27,6 +27,14 @@
#include <framework/otml/otml.h>
namespace
{
// for performance reasons we use statics vectors that are allocated on demand
CoordsBuffer s_coordsBuffer;
std::vector<Point> s_glyphsPositions(1);
std::vector<int> s_lineWidths(1);
}
void BitmapFont::load(const OTMLNodePtr& fontNode)
{
OTMLNodePtr textureNode = fontNode->at("texture");
@ -35,11 +43,12 @@ void BitmapFont::load(const OTMLNodePtr& fontNode)
m_glyphHeight = fontNode->valueAt<int>("height");
m_yOffset = fontNode->valueAt("y-offset", 0);
m_firstGlyph = fontNode->valueAt("first-glyph", 32);
m_glyphSpacing = fontNode->valueAt("spacing", Size(0,0));
m_glyphSpacing = fontNode->valueAt("spacing", Size(0, 0));
int spaceWidth = fontNode->valueAt("space-width", glyphSize.width());
// load font texture
m_texture = g_textures.getTexture(textureFile);
Size textureSize = m_texture->getSize();
if(OTMLNodePtr node = fontNode->get("fixed-glyph-width")) {
for(int glyph = m_firstGlyph; glyph < 256; ++glyph)
@ -68,7 +77,7 @@ void BitmapFont::load(const OTMLNodePtr& fontNode)
// calculate glyphs texture coords
int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
int numHorizontalGlyphs = textureSize.width() / glyphSize.width();
for(int glyph = m_firstGlyph; glyph < 256; ++glyph) {
m_glyphsTextureCoords[glyph].setRect(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
@ -86,11 +95,9 @@ void BitmapFont::drawText(const std::string& text, const Point& startPos)
void BitmapFont::drawText(const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align)
{
static CoordsBuffer coordsBuffer;
coordsBuffer.clear();
calculateDrawTextCoords(coordsBuffer, text, screenCoords, align);
g_painter->drawTextureCoords(coordsBuffer, m_texture);
s_coordsBuffer.clear();
calculateDrawTextCoords(s_coordsBuffer, text, screenCoords, align);
g_painter->drawTextureCoords(s_coordsBuffer, m_texture);
}
void BitmapFont::calculateDrawTextCoords(CoordsBuffer& coordsBuffer, const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align)
@ -103,7 +110,7 @@ void BitmapFont::calculateDrawTextCoords(CoordsBuffer& coordsBuffer, const std::
// map glyphs positions
Size textBoxSize;
const std::vector<Point>& glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize);
const auto& glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize);
for(int i = 0; i < textLenght; ++i) {
int glyph = (uchar)text[i];
@ -171,52 +178,49 @@ void BitmapFont::calculateDrawTextCoords(CoordsBuffer& coordsBuffer, const std::
const std::vector<Point>& BitmapFont::calculateGlyphsPositions(const std::string& text,
Fw::AlignmentFlag align,
Size *textBoxSize)
Size* textBoxSize)
{
// for performance reasons we use statics vectors that are allocated on demand
static std::vector<Point> glyphsPositions(1);
static std::vector<int> lineWidths(1);
int textLength = text.length();
int maxLineWidth = 0;
int lines = 0;
int glyph;
int i;
// return if there is no text
if(textLength == 0) {
if(textBoxSize)
textBoxSize->resize(0,m_glyphHeight);
return glyphsPositions;
textBoxSize->resize(0, m_glyphHeight);
return s_glyphsPositions;
}
// resize glyphsPositions vector when needed
if(textLength > (int)glyphsPositions.size())
glyphsPositions.resize(textLength);
// resize s_glyphsPositions vector when needed
if(textLength > (int)s_glyphsPositions.size())
s_glyphsPositions.resize(textLength);
// calculate lines width
if((align & Fw::AlignRight || align & Fw::AlignHorizontalCenter) || textBoxSize) {
lineWidths[0] = 0;
for(i = 0; i< textLength; ++i) {
s_lineWidths[0] = 0;
for(int i = 0; i < textLength; ++i) {
glyph = (uchar)text[i];
if(glyph == (uchar)'\n') {
lines++;
if(lines+1 > (int)lineWidths.size())
lineWidths.resize(lines+1);
lineWidths[lines] = 0;
// resize s_lineWidths vector when needed
if(lines+1 > (int)s_lineWidths.size())
s_lineWidths.resize(lines+1);
s_lineWidths[lines] = 0;
} else if(glyph >= 32) {
lineWidths[lines] += m_glyphsSize[glyph].width() ;
if((i+1 != textLength && text[i+1] != '\n')) // only add space if letter is not the last or before a \n.
lineWidths[lines] += m_glyphSpacing.width();
maxLineWidth = std::max<int>(maxLineWidth, lineWidths[lines]);
s_lineWidths[lines] += m_glyphsSize[glyph].width();
// only add space if letter is not the last or before a \n
if((i+1 != textLength && text[i+1] != '\n'))
s_lineWidths[lines] += m_glyphSpacing.width();
maxLineWidth = std::max<int>(maxLineWidth, s_lineWidths[lines]);
}
}
}
Point virtualPos(0, m_yOffset);
lines = 0;
for(i = 0; i < textLength; ++i) {
for(int i = 0; i < textLength; ++i) {
glyph = (uchar)text[i];
// new line or first glyph
@ -228,16 +232,16 @@ const std::vector<Point>& BitmapFont::calculateGlyphsPositions(const std::string
// calculate start x pos
if(align & Fw::AlignRight) {
virtualPos.x = (maxLineWidth - lineWidths[lines]);
virtualPos.x = (maxLineWidth - s_lineWidths[lines]);
} else if(align & Fw::AlignHorizontalCenter) {
virtualPos.x = (maxLineWidth - lineWidths[lines]) / 2;
virtualPos.x = (maxLineWidth - s_lineWidths[lines]) / 2;
} else { // AlignLeft
virtualPos.x = 0;
}
}
// store current glyph topLeft
glyphsPositions[i] = virtualPos;
s_glyphsPositions[i] = virtualPos;
// render only if the glyph is valid
if(glyph >= 32 && glyph != (uchar)'\n') {
@ -250,7 +254,7 @@ const std::vector<Point>& BitmapFont::calculateGlyphsPositions(const std::string
textBoxSize->setHeight(virtualPos.y + m_glyphHeight);
}
return glyphsPositions;
return s_glyphsPositions;
}
Size BitmapFont::calculateTextRectSize(const std::string& text)
@ -265,11 +269,12 @@ void BitmapFont::calculateGlyphsWidthsAutomatically(const ImagePtr& image, const
if(!image)
return;
int numHorizontalGlyphs = image->getSize().width() / glyphSize.width();
auto texturePixels = image->getPixels();
Size imageSize = image->getSize();
int numHorizontalGlyphs = imageSize.width() / glyphSize.width();
const auto& texturePixels = image->getPixels();
// small AI to auto calculate pixels widths
for(int glyph = m_firstGlyph; glyph< 256; ++glyph) {
for(int glyph = m_firstGlyph; glyph < 256; ++glyph) {
Rect glyphCoords(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
glyphSize.width(),
@ -279,7 +284,7 @@ void BitmapFont::calculateGlyphsWidthsAutomatically(const ImagePtr& image, const
int filledPixels = 0;
// check if all vertical pixels are alpha
for(int y = glyphCoords.top(); y <= glyphCoords.bottom(); ++y) {
if(texturePixels[(y * image->getSize().width() * 4) + (x*4) + 3] != 0)
if(texturePixels[(y * imageSize.width() * 4) + (x*4) + 3] != 0)
filledPixels++;
}
if(filledPixels > 0)
@ -293,51 +298,54 @@ void BitmapFont::calculateGlyphsWidthsAutomatically(const ImagePtr& image, const
std::string BitmapFont::wrapText(const std::string& text, int maxWidth)
{
std::string outText;
std::string line;
std::vector<std::string> words;
std::vector<std::string> wordsSplit = stdext::split(text);
// break huge words into small ones
for(const auto &word: wordsSplit) {
for(const auto& word: wordsSplit) {
int wordWidth = calculateTextRectSize(word).width();
if(wordWidth > maxWidth) {
std::string newWord;
for(uint j=0;j<word.length();++j) {
for(uint j = 0; j < word.length(); ++j) {
std::string candidate = newWord + word[j];
if(j != word.length() - 1)
candidate += "-";
candidate += '-';
int candidateWidth = calculateTextRectSize(candidate).width();
if(candidateWidth > maxWidth) {
newWord += "-";
newWord += '-';
words.push_back(newWord);
newWord = "";
newWord.clear();
}
newWord += word[j];
}
words.push_back(newWord);
} else
} else {
words.push_back(word);
}
}
// compose lines
for(const auto &word: words) {
std::string candidate = line + word;
int candidateWidth = calculateTextRectSize(candidate).width();
std::string line(words[0]);
for(ulong i = 1; i < words.size(); ++i)
{
const auto& word = words[i];
if(candidateWidth > maxWidth) {
if(!line.empty())
outText += line.substr(0, line.length()-1) + "\n";
line = "";
line.push_back(' ');
ulong lineSize = line.size();
line.append(word);
if(calculateTextRectSize(line).width() > maxWidth)
{
line.resize(lineSize);
line.back() = '\n';
outText.append(line);
line.assign(word);
}
line += word + " ";
}
outText += line;
outText = outText.substr(0, outText.length()-1);
outText.append(line);
return outText;
}

View File

@ -55,7 +55,7 @@ public:
std::string wrapText(const std::string& text, int maxWidth);
std::string getName() { return m_name; }
const std::string& getName() { return m_name; }
int getGlyphHeight() { return m_glyphHeight; }
const Rect* getGlyphsTextureCoords() { return m_glyphsTextureCoords; }
const Size* getGlyphsSize() { return m_glyphsSize; }
@ -79,4 +79,3 @@ private:
#endif

View File

@ -50,18 +50,16 @@ std::string date_time_string(const char* format/* = "%b %d %Y %H:%M:%S"*/)
char date[100];
std::time_t tnow;
std::time(&tnow);
std::tm *ts = std::localtime(&tnow);
std::tm* ts = std::localtime(&tnow);
std::strftime(date, 100, format, ts);
return std::string(date);
}
std::string dec_to_hex(uint64_t num)
{
std::string str;
std::ostringstream o;
o << std::hex << num;
str = o.str();
return str;
return o.str();
}
uint64_t hex_to_dec(const std::string& str)
@ -74,7 +72,7 @@ uint64_t hex_to_dec(const std::string& str)
bool is_valid_utf8(const std::string& src)
{
const unsigned char *bytes = (const unsigned char *)src.c_str();
const unsigned char* bytes = (const unsigned char*)src.c_str();
while(*bytes) {
if( (// ASCII
// use bytes[0] <= 0x7F to allow ASCII control characters
@ -146,7 +144,7 @@ bool is_valid_utf8(const std::string& src)
std::string utf8_to_latin1(const std::string& src)
{
std::string out;
for(uint i=0;i<src.length();) {
for(uint i = 0; i < src.length();) {
uchar c = src[i++];
if((c >= 32 && c < 128) || c == 0x0d || c == 0x0a || c == 0x09)
out += c;
@ -273,7 +271,7 @@ void replace_all(std::string& str, const std::string& search, const std::string&
std::vector<std::string> split(const std::string& str, const std::string& separators)
{
std::vector<std::string> splitted;
boost::split(splitted, str, boost::is_any_of(std::string(separators)));
boost::split(splitted, str, boost::is_any_of(separators));
return splitted;
}

View File

@ -63,11 +63,12 @@ std::string utf16_to_latin1(const std::wstring& src);
std::wstring latin1_to_utf16(const std::string& src);
#endif
// always returns at least one element in vector
std::vector<std::string> split(const std::string& str, const std::string& separators = " ");
template<typename T> std::vector<T> split(const std::string& str, const std::string& separators = " ") {
std::vector<std::string> splitted = split(str, separators);
std::vector<T> results(splitted.size());
for(uint i=0;i<splitted.size();++i)
for(uint i = 0; i < splitted.size(); ++i)
results[i] = safe_cast<T>(splitted[i]);
return results;
}

View File

@ -142,9 +142,9 @@ void UITextEdit::update(bool focusCursor)
// map glyphs positions
Size textBoxSize;
const std::vector<Point>& glyphsPositions = m_font->calculateGlyphsPositions(text, m_textAlign, &textBoxSize);
const Rect *glyphsTextureCoords = m_font->getGlyphsTextureCoords();
const Size *glyphsSize = m_font->getGlyphsSize();
const auto& glyphsPositions = m_font->calculateGlyphsPositions(text, m_textAlign, &textBoxSize);
const Rect* glyphsTextureCoords = m_font->getGlyphsTextureCoords();
const Size* glyphsSize = m_font->getGlyphsSize();
int glyph;
// update rect size

View File

@ -42,7 +42,7 @@ public:
void setCursorVisible(bool enable) { m_cursorVisible = enable; }
void setChangeCursorImage(bool enable) { m_changeCursorImage = enable; }
void setTextHidden(bool hidden);
void setValidCharacters(const std::string validCharacters) { m_validCharacters = validCharacters; }
void setValidCharacters(const std::string& validCharacters) { m_validCharacters = validCharacters; }
void setShiftNavigation(bool enable) { m_shiftNavigation = enable; }
void setMultiline(bool enable) { m_multiline = enable; }
void setMaxLength(uint maxLength) { m_maxLength = maxLength; }