engine/src/FontManager/FontManager.cpp
2013-02-03 21:24:01 +00:00

407 lines
10 KiB
C++

#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