#include "include/FontManager/FontManager.h" #include "include/Engine.h" #include <boost/algorithm/string.hpp> namespace SE { const float CONST_HEIGHT_COEF = 1.0f; const int CONST_MAX_FONT_STACK_SIZE = 10; TFontManager::~TFontManager() { *Console<<"TFontManager deleting..."; } void TFontManager::Serialize(boost::property_tree::ptree& propertyTree) { BOOST_FOREACH(boost::property_tree::ptree::value_type &v, propertyTree.get_child("Fonts")) { std::string fontName = v.second.get<std::string>("FontName"); std::string bitmapFileName = v.second.get<std::string>("BitmapFileName"); std::string charmapFileName = v.second.get<std::string>("CharmapFileName"); AddFont(fontName, bitmapFileName, charmapFileName); } } void TFontManager::AddFont(const std::string& fontName, const std::string& bitmapFile, const std::string& charmapFile) { if (FontMap.count(fontName) > 0) { throw ErrorToLog("Trying to add font twice or some font files not found!" + fontName); } TFont& currentFont = FontMap[fontName]; std::string texName = GetFileName(bitmapFile); currentFont.TexName = texName; ResourceManager->TexList.AddTexture(bitmapFile); currentFont.SheetWidth = ResourceManager->TexList.GetTextureWidth(texName); currentFont.SheetHeight = ResourceManager->TexList.GetTextureHeight(texName); cardinal byteCount; boost::shared_array<char> charmapFileArr = boost::shared_array<char>(CreateMemFromFile<char>(ResourceManager->PathToResources+charmapFile, byteCount)); //Need to rewrite this code :( TFontParams fontParams; cardinal character; std::stringstream charmapFileStream; charmapFileStream.write(&charmapFileArr[0], byteCount); while(!charmapFileStream.eof()) { charmapFileStream>>character; charmapFileStream>>fontParams.ShiftX; charmapFileStream>>fontParams.ShiftY; charmapFileStream>>fontParams.InternalShiftX; charmapFileStream>>fontParams.InternalShiftY; charmapFileStream>>fontParams.BitmapWidth; charmapFileStream>>fontParams.BitmapHeight; charmapFileStream>>fontParams.Advance; currentFont.CharMap[character] = fontParams; } } void TFontManager::PushFont(const std::string& fontName) { if (FontStack.size() >= CONST_MAX_FONT_STACK_SIZE) { throw ErrorToLog("Error: font stack overflow!"); } FontStack.push(fontName); } void TFontManager::PopFont() { if (FontStack.size() == 0) { throw ErrorToLog("Error: font stack underflow!"); } FontStack.pop(); } std::string TFontManager::GetCurrentFontName() { if (FontStack.size() == 0) { throw ErrorToLog("Error: font stack underflow!"); } return FontStack.top(); } std::string TFontManager::GetCurrentFontTextureName() { return FontMap[GetCurrentFontName()].TexName; } float TFontManager::DrawChar(vec2 pos, cardinal character) { //Also see DrawCharToVBO std::string fontName = GetCurrentFontName(); if (FontMap.count(fontName) == 0) { throw ErrorToLog("Trying to use unknown font! " + fontName); } TFont& currentFont = FontMap[fontName]; TFontParams& fontParams = currentFont.CharMap[character]; int scale_y = currentFont.SheetHeight; int scale_x = currentFont.SheetWidth; float height = scale_y*fontParams.BitmapHeight; float width = scale_x*fontParams.BitmapWidth; vec2 p1 = pos + vec2(+ scale_x*fontParams.InternalShiftX, -height- scale_y*fontParams.InternalShiftY); vec2 p2 = pos + vec2(width + scale_x*fontParams.InternalShiftX, - scale_y* fontParams.InternalShiftY); vec2 t1 = vec2(fontParams.ShiftX, 1 - fontParams.ShiftY - fontParams.BitmapHeight - fontParams.InternalShiftY); vec2 t2 = vec2(fontParams.ShiftX + fontParams.BitmapWidth, 1 - fontParams.ShiftY - fontParams.InternalShiftY); Renderer->DrawRect(p1, p2, t1, t2); return fontParams.Advance*scale_x; } float TFontManager::DrawCharToVBO(vec2 pos, cardinal character, TTriangleList& triangleList) { //Also see DrawChar std::string fontName = GetCurrentFontName(); if (FontMap.count(fontName) == 0) { throw ErrorToLog("Trying to use unknown font! " + fontName); } TFont& currentFont = FontMap[fontName]; TFontParams& fontParams = currentFont.CharMap[character]; int scale_y = currentFont.SheetHeight; int scale_x = currentFont.SheetWidth; float height = scale_y*fontParams.BitmapHeight; float width = scale_x*fontParams.BitmapWidth; vec2 p1 = pos + vec2(+ scale_x*fontParams.InternalShiftX, -height - scale_y*fontParams.InternalShiftY); vec2 p2 = pos + vec2(width + scale_x*fontParams.InternalShiftX, - scale_y* fontParams.InternalShiftY); vec2 t1 = vec2(fontParams.ShiftX, 1 - fontParams.ShiftY - fontParams.BitmapHeight - fontParams.InternalShiftY); vec2 t2 = vec2(fontParams.ShiftX + fontParams.BitmapWidth, 1 - fontParams.ShiftY - fontParams.InternalShiftY); triangleList.Data += MakeDataTriangleList(p1, p2, t1, t2); return fontParams.Advance*scale_x; } vec2 TFontManager::FitStringToBoxWithWordWrap(vec2 posFrom, vec2 posTo, TTextBasicAreaParams params, std::string& str) { std::string fontName = GetCurrentFontName(); float intervalY = CONST_HEIGHT_COEF * params.Height; size_t rows = 1; //Apply padding: posFrom.v[0] += params.HorizontalPadding; posTo.v[0] -= params.HorizontalPadding; posFrom.v[1] += params.VerticalPadding; posTo.v[1] -= params.VerticalPadding; float maxWidth = posTo.v[0] - posFrom.v[0]; //cardinal p = 0; vec2 cursor; std::vector<std::string> explodedByParagraph; boost::split(explodedByParagraph, str, boost::is_any_of("\n"), boost::token_compress_on); std::string result; for (size_t i=0; i<explodedByParagraph.size(); i++) { std::vector<std::string> explodedByWord; boost::split(explodedByWord, explodedByParagraph[i], boost::is_space(), boost::token_compress_on); for (size_t j=0; j< explodedByWord.size(); j++) { std::string s = explodedByWord[j]; float adv = GetTextAdvance(s); if (adv + cursor.v[0] < maxWidth) { result += s + " "; cursor.v[0] += adv + GetCharAdvance(' '); } else { if (adv < maxWidth) { result += "\n" + s + " "; cursor.v[0] = adv + GetCharAdvance(' '); } else { for (int k=0; k<s.size(); k++) { result += s[k]; cursor.v[0] += GetCharAdvance(s[k]); if (cursor.v[0] > maxWidth) { cursor.v[0] = 0; result += "\n"; } } } } } result += "\n"; cursor.v[0] = 0; } //Erase last symbol \n result.erase(result.end()-1, result.end()); str = result; size_t found = str.find_first_of('\n'); while (found != std::string::npos) { rows++; found = str.find_first_of('\n', found + 1); } vec2 result_vec = vec2(posFrom.v[0], posFrom.v[1] + intervalY*rows); if (params.TextHorizontalAlignment == THA_RIGHT) { result_vec.v[0] = posTo.v[0]; } else if (params.TextHorizontalAlignment == THA_CENTER) { result_vec.v[0] = (posTo.v[0] + posFrom.v[0])*0.5f; } if (params.TextVerticalAlignment == TVA_TOP) { result_vec.v[1] = posTo.v[1]; } else if (params.TextVerticalAlignment == TVA_CENTER) { result_vec.v[1] = (posTo.v[1] + posFrom.v[1])*0.5f; } return result_vec; } TTriangleList TFontManager::DrawStringToVBO(vec2 pos, TTextBasicAreaParams params, const std::string& str) { std::wstring ws; utf8toWStr(ws, str); std::string fontName = GetCurrentFontName(); float width; TTriangleList triangleList; std::vector<std::wstring> rowArr; boost::split(rowArr, ws, boost::algorithm::is_any_of("\n")); vec2 startPos = pos; float rowsHeight = rowArr.size() * CONST_HEIGHT_COEF*params.Height; BOOST_FOREACH(auto& rowStr, rowArr) { float rowWidth = GetTextAdvance(rowStr); for (cardinal i=0; i<rowStr.size(); i++) { vec2 realPos = pos; if (params.TextHorizontalAlignment == THA_RIGHT) { realPos.v[0] = realPos.v[0] - rowWidth; } else if (params.TextHorizontalAlignment == THA_CENTER) { realPos.v[0] = realPos.v[0] - rowWidth*0.5f; realPos.v[0] = floorf(realPos.v[0]); } if (params.TextVerticalAlignment == TVA_CENTER) { realPos.v[1] = realPos.v[1] + rowsHeight*0.5f; realPos.v[1] = floorf(realPos.v[1]); } width = DrawCharToVBO(realPos, rowStr[i], triangleList); pos += vec2(width, 0); } pos.v[1] -= CONST_HEIGHT_COEF*params.Height; pos.v[0] = startPos.v[0]; } triangleList.RefreshBuffer(); return triangleList; } void TFontManager::DrawString(vec2 pos, TTextBasicAreaParams params, const std::string& str) { TTriangleList triangleList = DrawStringToVBO(pos, params, str); Renderer->DrawTriangleList(triangleList); } void TFontManager::DrawTextInBox(vec2 posFrom, vec2 posTo, TTextBasicAreaParams params, std::string str, bool wordWrap) { vec2 realPosFrom; if (wordWrap) { realPosFrom = FitStringToBoxWithWordWrap(posFrom, posTo, params, str); } else { //realPosFrom = FitStringToBox(posFrom, posTo, params, str); throw ErrorToLog("Word wrap not supported!"); } DrawString(realPosFrom, params, str); } TTriangleList TFontManager::DrawTextInBoxToVBO(vec2 posFrom, vec2 posTo, TTextBasicAreaParams params, std::string str, bool wordWrap) { vec2 realPosFrom; if (wordWrap) { realPosFrom = FitStringToBoxWithWordWrap(posFrom, posTo, params, str); } else { throw ErrorToLog("Word wrap not supported!"); //realPosFrom = FitStringToBox(posFrom, posTo, params, str); } return DrawStringToVBO(realPosFrom, params, str); } } //namespace SE