注:2014年12月23日有內存/性能優化更新,內容在下面分割線後html
搞了幾個小時,這個頭疼的問題,我給出代碼吧。算法
找到 性能優化
libcocos2d/platform/winrt/CCFreeTypeFont.cpp函數
(其中libcocos2d是項目名)而後將其中的函數 addWord 替換爲我提供的便可。實在找不到文件的同窗直接搜索吧。性能
須要注意的是我只簡單處理了一下,因此中文下只支持UTF8字符串,非UTF8字符串會出問題。固然英文環境下任然是用默認邏輯。優化
個人cocos2dx版本是 3.2,若是你的版本不是這個,存在個別差別,那就本身改改吧。spa
但願你們拿走代碼的時候在下面評論一下,好提升我分享的積極性,你懂得。調試
FT_Error CCFreeTypeFont::addWord(const std::string& word) { std::vector<TGlyph> glyphs; // glyphs for the word FT_BBox bbox; // bounding box containing all of the glyphs in the word int maxWidth = m_inWidth ? m_inWidth : m_windowWidth; std::string newWord; if(m_currentLine->width > 0) { newWord = ' ' + word; } else { newWord = word; } FT_Error error = initWordGlyphs(glyphs, newWord, m_currentLine->pen); if(!error) { compute_bbox(glyphs, &bbox); /*判斷添加進去後整個line是否顯示寬度大於設定寬度,是的話進行截取*/ if (Application::getInstance()->getCurrentLanguage() == LanguageType::CHINESE && bbox.xMax > maxWidth) { std:size_t start = 0, end = word.length(); while (true) { while (true)//這個字符比最寬還要寬,則進行截取 { end--; FT_BBox validBBox = bbox; std::vector<TGlyph> validGlyphs; FTLineInfo validLine = FTLineInfo(); validLine.width = 0; validLine.pen.x = 0; validLine.pen.y = 0; //對UTF8字符進行切割 if (end != word.length()) { while (true) { unsigned char utf8charpart = word.at(end - 1); if ((utf8charpart & 0x80) != 0 && (utf8charpart & 0xe0) != 0xc0 && (utf8charpart & 0xf0) != 0xe0 && (utf8charpart & 0xf8) != 0xf0) { end--; } else { end--; break; } } } std::string validStr = word.substr(start, end - start); FT_Error validError = initWordGlyphs(validGlyphs, validStr, validLine.pen); if (validError) break; compute_bbox(validGlyphs, &validBBox); if (validBBox.xMax <= maxWidth) { m_currentLine->glyphs.insert(validLine.glyphs.end(), validGlyphs.begin(), validGlyphs.end()); if (m_currentLine->width == 0) { m_currentLine->bbox = validBBox; } else { m_currentLine->bbox.xMax = validBBox.xMax; } break; } } start = end; end = word.length() + 1; if (start == end - 1) break; bbox = FT_BBox(); endLine(); newLine(); } } else { if (m_currentLine->width == 0 || bbox.xMax <= maxWidth) { m_currentLine->glyphs.insert(m_currentLine->glyphs.end(), glyphs.begin(), glyphs.end()); if (m_currentLine->width == 0) { m_currentLine->bbox = bbox; } else { m_currentLine->bbox.xMax = bbox.xMax; } m_currentLine->width = m_currentLine->bbox.xMax - m_currentLine->bbox.xMin; } else { endLine(); newLine(); addWord(word); } } } return error; }
========================================快樂的分割線 ========================================code
謝謝 @請讓我過好很差 的反饋。我仔細調試後發現形成內存佔用過大的緣由是中途逐字符計算換行加載成的圖像沒有釋放掉。而且算法是先計算整個字符串長度,而後逐漸從尾部減少一個字符重新計算,當小於最大寬度時候進行換行重新執行上面的計算。這種算法性能很低,所以我改成了從第一個字符開始計算,當算的字符超過一行,則使用上個字符的位置進行換行。orm
其實還有優化的空間,由於逐字符計算調用的是作事情比較多餘的函數,但我沒有那麼多時間細扣了,下面貼出代碼,與分割線以前的版本相似替換系統的 addWord 函數便可:
FT_Error CCFreeTypeFont::addWord(const std::string& word) { std::vector<TGlyph> glyphs; // glyphs for the word FT_BBox bbox; // bounding box containing all of the glyphs in the word int maxWidth = m_inWidth ? m_inWidth : m_windowWidth; std::string newWord; if(m_currentLine->width > 0) { newWord = ' ' + word; } else { newWord = word; } FT_Error error = initWordGlyphs(glyphs, newWord, m_currentLine->pen); if(!error) { compute_bbox(glyphs, &bbox); /*判斷添加進去後整個line是否顯示寬度大於設定寬度,是的話進行截取*/ if (Application::getInstance()->getCurrentLanguage() == LanguageType::CHINESE && bbox.xMax > maxWidth) { std:size_t start = 0, end = -1, lastValidEnd = 0; while (true) { while (true)//這個字符比最寬還要寬,則進行截取 { end++; FT_BBox validBBox = bbox; std::vector<TGlyph> validGlyphs; FTLineInfo validLine; validLine.width = 0; validLine.pen.x = 0; validLine.pen.y = 0; //對UTF8字符進行切割 while (true) { end++; if (end == word.length()) break; unsigned char utf8charpart = word.at(end); if (!((utf8charpart & 0x80) != 0 && (utf8charpart & 0xe0) != 0xc0 && (utf8charpart & 0xf0) != 0xe0 && (utf8charpart & 0xf8) != 0xf0)) { break; } } std::string validStr = word.substr(start, end - start); FT_Error validError = initWordGlyphs(validGlyphs, validStr, validLine.pen); if (validError) break; compute_bbox(validGlyphs, &validBBox); if (validBBox.xMax < maxWidth && end != word.length()) { lastValidEnd = end; for (auto glyph = validGlyphs.begin(); glyph != validGlyphs.end(); ++glyph) { FT_Done_Glyph(glyph->image); } continue; } else { std::string validStr = word.substr(start, lastValidEnd - start); lastValidEnd = end; FT_Error validError = initWordGlyphs(validGlyphs, validStr, validLine.pen); if (validError) break; compute_bbox(validGlyphs, &validBBox); m_currentLine->glyphs.insert(validLine.glyphs.end(), validGlyphs.begin(), validGlyphs.end()); if (m_currentLine->width == 0) { m_currentLine->bbox = validBBox; } else { m_currentLine->bbox.xMax = validBBox.xMax; } break; } } start = lastValidEnd; end = lastValidEnd; if (end == word.length()) break; FT_BBox emptybbox; bbox = emptybbox; endLine(); newLine(); } } else { if (m_currentLine->width == 0 || bbox.xMax <= maxWidth) { m_currentLine->glyphs.insert(m_currentLine->glyphs.end(), glyphs.begin(), glyphs.end()); if (m_currentLine->width == 0) { m_currentLine->bbox = bbox; } else { m_currentLine->bbox.xMax = bbox.xMax; } m_currentLine->width = m_currentLine->bbox.xMax - m_currentLine->bbox.xMin; } else { endLine(); newLine(); addWord(word); } } } return error; }