00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "KeosFontManager.h"
00023 #include "KeosLogger.h"
00024 #include "KeosRenderSystem.h"
00025 #include "KeosColor.h"
00026 #include "KeosGraphicString.h"
00027 #include "KeosMediaManager.h"
00028 #include <ft2build.h>
00029 #include FT_FREETYPE_H
00030
00031 namespace Keos
00032 {
00033
00034
00035
00036
00037
00038
00039 CFontManager::CFontManager()
00040 {}
00041
00042
00043 CFontManager::~CFontManager()
00044 {
00045 UnloadFonts();
00046 }
00047
00048
00049 void CFontManager::Initialize()
00050 {
00051
00052 TDeclarationElement Decl[] =
00053 {
00054 {0, ELT_USAGE_POSITION, ELT_TYPE_FLOAT3},
00055 {0, ELT_USAGE_DIFFUSE, ELT_TYPE_COLOR},
00056 {0, ELT_USAGE_TEXCOORD0, ELT_TYPE_FLOAT2}
00057 };
00058 m_Declaration = Renderer->CreateVertexDeclaration(Decl);
00059
00060
00061 m_VertexBuffer = Renderer->CreateVertexBuffer<TVertex>(NbCharMax * 4, BUF_DYNAMIC);
00062
00063
00064 std::vector<TIndex> Indices;
00065 for (TIndex i = 0; i < NbCharMax; ++i)
00066 {
00067 Indices.push_back(i * 4 + 0);
00068 Indices.push_back(i * 4 + 1);
00069 Indices.push_back(i * 4 + 2);
00070 Indices.push_back(i * 4 + 2);
00071 Indices.push_back(i * 4 + 1);
00072 Indices.push_back(i * 4 + 3);
00073 }
00074 m_IndexBuffer = Renderer->CreateIndexBuffer((int)Indices.size(), 0, &Indices[0]);
00075 }
00076
00077
00078 void CFontManager::LoadFont(const String& strFontFile, const String& strFontName, int nQuality)
00079 {
00080
00081 ILogger::Log("Load of the font (size=%d): %s", nQuality, strFontFile.c_str());
00082
00083
00084 CFile FontFile = CMediaManager::Instance().FindMedia(CFile(strFontFile));
00085
00086 uint nFontSize = nQuality;
00087
00088
00089
00090 const String strChars( "abcdefghijklmnopqrstuvwxyz"
00091 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00092 "1234567890~!@#$%^&*()-=+;:"
00093 "'\",./?[]|\\ <>`\xFF");
00094
00095
00096 const uint nMargin = 3;
00097 uint nImageHeight = 0, nImageWidth = 256;
00098
00099
00100 FT_Library library;
00101 if (FT_Init_FreeType(&library) != 0)
00102 LOADINGFAILED_EXCEPT(strFontFile, "FreeType2 error : Could not initialize FreeType2 library", "CFontManager::LoadFont");
00103
00104
00105 FT_Face face;
00106 if (FT_New_Face(library, FontFile.Fullname().c_str(), 0, &face) != 0)
00107 LOADINGFAILED_EXCEPT(strFontFile, "FreeType2 error : Could not load font file", "CFontManager::LoadFont");
00108
00109
00110 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) ||
00111 !(face->face_flags & FT_FACE_FLAG_HORIZONTAL))
00112 LOADINGFAILED_EXCEPT(strFontFile, "FreeType2 error : Error setting font size", "CFontManager::LoadFont");
00113
00114
00115 FT_Set_Pixel_Sizes(face, (FT_UInt)nFontSize, 0);
00116
00117
00118
00119
00120
00121 int nMaxDescent = 0, nMaxAscent = 0;
00122 uint nSpaceOnLine = nImageWidth - nMargin, nLines = 1;
00123
00124 for (uint i = 0; i < strChars.size(); ++i)
00125 {
00126
00127 uint nCharIndex = FT_Get_Char_Index(face, static_cast<unsigned int>(strChars[i]));
00128 if (strChars[i] == '\xFF')
00129 nCharIndex = 0;
00130
00131
00132 FT_Load_Glyph(face, (FT_UInt)nCharIndex, FT_LOAD_DEFAULT);
00133 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
00134
00135 uint nAdvance = (face->glyph->metrics.horiAdvance >> 6) + nMargin;
00136
00137 if (nAdvance > nSpaceOnLine)
00138 {
00139 nSpaceOnLine = nImageWidth - nMargin;
00140 ++nLines;
00141 }
00142 nSpaceOnLine -= nAdvance;
00143
00144 nMaxAscent = std::max(face->glyph->bitmap_top, nMaxAscent);
00145 nMaxDescent = std::max(face->glyph->bitmap.rows -
00146 face->glyph->bitmap_top, nMaxDescent);
00147 }
00148
00149 m_Fonts[strFontName].LineHeight = nMaxAscent + nMaxDescent;
00150
00151
00152 uint nNeededImageHeight = (nMaxAscent + nMaxDescent + nMargin) * nLines + nMargin;
00153
00154 nImageHeight = 16;
00155 while (nImageHeight < nNeededImageHeight)
00156 nImageHeight *= 2;
00157
00158
00159 unsigned char* pImage = new unsigned char[nImageHeight * nImageWidth];
00160 for (uint i = 0; i < nImageHeight * nImageWidth; ++i)
00161 pImage[i] = 0;
00162
00163 m_Fonts[strFontName].TextureLineHeight = static_cast<float>(m_Fonts[strFontName].LineHeight) / nImageHeight;
00164
00165
00166 m_Fonts[strFontName].Glyphs = new Glyph[strChars.size()];
00167 for (uint i = 0; i != 256; ++i)
00168 m_Fonts[strFontName].GlyphsTable[i] = NULL;
00169
00170
00171 uint x = nMargin, y = nMargin + nMaxAscent;
00172
00173
00174 for (uint i = 0; i < strChars.size(); ++i)
00175 {
00176 uint nCharIndex = FT_Get_Char_Index(face, static_cast<unsigned int>(strChars[i]));
00177 if (strChars[i] == '\xFF')
00178 nCharIndex = 0;
00179
00180
00181 FT_Load_Glyph(face, (FT_UInt)nCharIndex, FT_LOAD_DEFAULT);
00182 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
00183
00184
00185 uint nAdvance = (face->glyph->metrics.horiAdvance >> 6) + nMargin;
00186 if (nAdvance > nImageWidth - x)
00187 {
00188 x = nMargin;
00189 y += (nMaxAscent + nMaxDescent + nMargin);
00190 }
00191
00192 m_Fonts[strFontName].Glyphs[i].Tex_x1 = static_cast<float>(x) / nImageWidth;
00193 m_Fonts[strFontName].Glyphs[i].Tex_x2 = static_cast<float>(x + (nAdvance - nMargin)) / nImageWidth;
00194 m_Fonts[strFontName].Glyphs[i].Tex_y1 = static_cast<float>(y - nMaxAscent) / nImageHeight;
00195 m_Fonts[strFontName].Glyphs[i].Advance = (nAdvance - nMargin);
00196
00197 m_Fonts[strFontName].GlyphsTable[(unsigned char)strChars[i]] = m_Fonts[strFontName].Glyphs + i;
00198
00199
00200
00201 for (int nRow = 0; nRow < face->glyph->bitmap.rows; ++nRow)
00202 {
00203 for (int nPixel = 0; nPixel < face->glyph->bitmap.width; ++nPixel)
00204 {
00205 pImage[(x + face->glyph->bitmap_left + nPixel) +
00206 (y - face->glyph->bitmap_top + nRow) * nImageWidth] =
00207 face->glyph->bitmap.buffer[nPixel + nRow * face->glyph->bitmap.pitch];
00208 }
00209 }
00210
00211 x += nAdvance;
00212 }
00213
00214
00215
00216 Glyph* pDefaultGlyph = m_Fonts[strFontName].GlyphsTable[(unsigned char)'\xFF'];
00217
00218 if (pDefaultGlyph == NULL)
00219 throw std::runtime_error("Font file contains no default glyph");
00220 for (uint i = 0; i != 256; ++i)
00221 {
00222 if (m_Fonts[strFontName].GlyphsTable[i] == NULL)
00223 m_Fonts[strFontName].GlyphsTable[i] = pDefaultGlyph;
00224 }
00225
00226 CImage ImgFont(TVector2I(nImageWidth, nImageHeight), PXF_L8, pImage);
00227 delete[] pImage;
00228
00229
00230
00231
00232 CImage ImgFont2(TVector2I(nImageWidth, nImageHeight), PXF_A8L8);
00233 for (uint i = 0; i < nImageWidth; ++i)
00234 for (uint j = 0; j < nImageHeight; ++j)
00235 {
00236 unsigned char CurPixel[1];
00237 ImgFont.GetPixel(i, j, CurPixel);
00238 ImgFont2.SetPixel(i, j, CColor(CurPixel[0], CurPixel[0], CurPixel[0], CurPixel[0]));
00239 }
00240
00241
00242 m_Fonts[strFontName].Texture.CreateFromImage(ImgFont2, PXF_A8L8, TEX_NOMIPMAP, strFontName);
00243
00244 FT_Done_FreeType(library);
00245 }
00246
00247
00248 void CFontManager::UnloadFonts()
00249 {
00250 for (
00251 TFontsMap::iterator it = m_Fonts.begin();
00252 it != m_Fonts.end();
00253 ++it )
00254 {
00255 delete[] it->second.Glyphs;
00256 }
00257 m_Fonts.clear();
00258 }
00259
00260
00261 void CFontManager::DrawString(const CGraphicString& String)
00262 {
00263
00264 if (String.Text == "")
00265 return;
00266
00267
00268 if (!m_Declaration)
00269 Initialize();
00270
00271 if (m_Fonts.find(String.Font) == m_Fonts.end())
00272 LOADINGFAILED_EXCEPT(String.Font, "This font has not been loaded with LoadFont function", "CFontManager::GetFont");
00273
00274
00275 const TFont& CurFont = m_Fonts[String.Font];
00276
00277
00278 float x = static_cast<float>(String.Position.x);
00279 float y = static_cast<float>(String.Position.y);
00280 unsigned long Color = Renderer->ConvertColor(String.Color);
00281
00282
00283 TVertex* Vertices = m_VertexBuffer.Lock(0, 0, LOCK_WRITEONLY);
00284
00285
00286 int nbChars = 0;
00287 for (String::const_iterator i = String.Text.begin(); (i != String.Text.end()) && (nbChars < NbCharMax); ++i)
00288 {
00289 unsigned char c = *i;
00290 Glyph* pGlyph = CurFont.GlyphsTable[c];
00291
00292
00293 switch (c)
00294 {
00295 case '\n' :
00296 x = static_cast<float>(String.Position.x);
00297 y += CurFont.LineHeight;
00298 continue;
00299
00300 case '\r' :
00301 x = static_cast<float>(String.Position.x);
00302 continue;
00303
00304 case '\t' :
00305 x += 4 * CurFont.GlyphsTable[' ']->Advance;
00306 continue;
00307
00308
00309 case '\v' :
00310 y += 4 * CurFont.LineHeight;
00311 continue;
00312
00313 case ' ' :
00314 x += CurFont.GlyphsTable[' ']->Advance;
00315 continue;
00316 }
00317
00318
00319 Vertices[nbChars * 4 + 0].Position.Set(x, y, 0);
00320 Vertices[nbChars * 4 + 1].Position.Set(x + pGlyph->Advance, y, 0);
00321 Vertices[nbChars * 4 + 2].Position.Set(x, y + CurFont.LineHeight, 0);
00322 Vertices[nbChars * 4 + 3].Position.Set(x + pGlyph->Advance, y + CurFont.LineHeight, 0);
00323
00324
00325 Vertices[nbChars * 4 + 0].Diffuse = Color;
00326 Vertices[nbChars * 4 + 1].Diffuse = Color;
00327 Vertices[nbChars * 4 + 2].Diffuse = Color;
00328 Vertices[nbChars * 4 + 3].Diffuse = Color;
00329
00330
00331 Vertices[nbChars * 4 + 0].TexCoords.Set(pGlyph->Tex_x1, pGlyph->Tex_y1);
00332 Vertices[nbChars * 4 + 1].TexCoords.Set(pGlyph->Tex_x2, pGlyph->Tex_y1);
00333 Vertices[nbChars * 4 + 2].TexCoords.Set(pGlyph->Tex_x1, pGlyph->Tex_y1 + CurFont.TextureLineHeight);
00334 Vertices[nbChars * 4 + 3].TexCoords.Set(pGlyph->Tex_x2, pGlyph->Tex_y1 + CurFont.TextureLineHeight);
00335
00336 x += pGlyph->Advance;
00337 ++nbChars;
00338 }
00339
00340
00341 m_VertexBuffer.Unlock();
00342
00343
00344
00345 Renderer->SetupAlphaBlending(BLEND_SRCALPHA, BLEND_INVSRCALPHA);
00346 Renderer->SetupTextureUnit(0, TXO_COLOR_MODULATE, TXA_TEXTURE, TXA_DIFFUSE);
00347 Renderer->SetupTextureUnit(0, TXO_ALPHA_MODULATE, TXA_TEXTURE, TXA_DIFFUSE);
00348 Renderer->Enable(RENDER_ALPHABLEND, true);
00349 Renderer->Enable(RENDER_ZWRITE, false);
00350
00351
00352 Renderer->SetDeclaration(m_Declaration);
00353 Renderer->SetTexture(0, CurFont.Texture.GetTextureBase());
00354 Renderer->SetVertexBuffer(0, m_VertexBuffer);
00355 Renderer->SetIndexBuffer(m_IndexBuffer);
00356 Renderer->DrawIndexedPrimitives(PT_TRIANGLELIST, 0, nbChars * 2);
00357 Renderer->SetTexture(0, NULL);
00358
00359
00360 Renderer->Enable(RENDER_ZWRITE, true);
00361 Renderer->Enable(RENDER_ALPHABLEND, false);
00362 }
00363
00364
00365 TVector2I CFontManager::GetStringPixelSize(const CGraphicString& String)
00366 {
00367
00368 if (String.Text == "")
00369 return TVector2I(0, 0);
00370
00371 if (m_Fonts.find(String.Font) == m_Fonts.end())
00372 LOADINGFAILED_EXCEPT(String.Font, "This font has not been loaded with LoadFont function", "CFontManager::GetFont");
00373
00374
00375 const TFont& CurFont = m_Fonts[String.Font];
00376
00377
00378 std::vector<int> Lengths;
00379
00380
00381 TVector2I Size(0, 0);
00382
00383 unsigned char c;
00384
00385
00386 for (std::string::const_iterator i = String.Text.begin(); i != String.Text.end(); ++i)
00387 {
00388 c = *i;
00389
00390 switch (c)
00391 {
00392 case '\n' :
00393 Lengths.push_back(Size.x);
00394 Size.y += (int)CurFont.LineHeight;
00395 Size.x = 0;
00396 break;
00397
00398 case '\r' :
00399 Lengths.push_back(Size.x);
00400 Size.x = 0;
00401 break;
00402
00403 case '\t' :
00404 Size.x += (int)(4 * CurFont.GlyphsTable[' ']->Advance);
00405 break;
00406
00407
00408 case '\v' :
00409 Size.y += (int)(4 * CurFont.LineHeight);
00410 break;
00411
00412 default :
00413 Size.x += (int)CurFont.GlyphsTable[c]->Advance;
00414 break;
00415 }
00416 }
00417
00418 if (c != '\n' && c != '\v' && c != '\r')
00419 Size.y += (int)CurFont.LineHeight;
00420
00421 Lengths.push_back(Size.x);
00422 Size.x = *std::max_element(Lengths.begin(), Lengths.end());
00423
00424 return Size;
00425 }
00426
00427
00428 size_t CFontManager::GetFontHeight(const String& strFontName)
00429 {
00430 if (m_Fonts.find(strFontName) == m_Fonts.end())
00431 LOADINGFAILED_EXCEPT(strFontName, "This font has not been loaded with LoadFont function", "CFontManager::GetFont");
00432
00433
00434 return m_Fonts[strFontName].LineHeight;
00435 }
00436
00437 }