00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00024
00026
00028 #include <SFML/Graphics/FontManager.hpp>
00029 #include <SFML/Graphics/Color.hpp>
00030 #include <SFML/Graphics/GraphicsDevice.hpp>
00031 #include <SFML/Graphics/Image.hpp>
00032 #include <SFML/Window/OpenGLCaps.hpp>
00033 #include <ft2build.h>
00034 #include FT_FREETYPE_H
00035 #include FT_GLYPH_H
00036 #include <iostream>
00037 #include <vector>
00038
00039
00040 namespace
00041 {
00045 FT_Library Library = NULL;
00046
00050 wchar_t DefaultCharset[] =
00051 {
00052 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
00053 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
00054 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
00055 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
00056 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
00057 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
00058 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
00059 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
00060 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
00061 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
00062 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
00063 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
00064 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
00065 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
00066 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
00067 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
00068 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
00069 252, 253, 254, 255, 0
00070 };
00071
00075 std::string GetErrorDesc(FT_Error Error)
00076 {
00077 switch (Error)
00078 {
00079
00080 case FT_Err_Cannot_Open_Resource : return "cannot open resource";
00081 case FT_Err_Unknown_File_Format : return "unknown file format";
00082 case FT_Err_Invalid_File_Format : return "broken file";
00083 case FT_Err_Invalid_Version : return "invalid FreeType version";
00084 case FT_Err_Lower_Module_Version : return "module version is too low";
00085 case FT_Err_Invalid_Argument : return "invalid argument";
00086 case FT_Err_Unimplemented_Feature : return "unimplemented feature";
00087 case FT_Err_Invalid_Table : return "broken table";
00088 case FT_Err_Invalid_Offset : return "broken offset within table";
00089
00090
00091 case FT_Err_Invalid_Glyph_Index : return "invalid glyph index";
00092 case FT_Err_Invalid_Character_Code : return "invalid character code";
00093 case FT_Err_Invalid_Glyph_Format : return "unsupported glyph image format";
00094 case FT_Err_Cannot_Render_Glyph : return "cannot render this glyph format";
00095 case FT_Err_Invalid_Outline : return "invalid outline";
00096 case FT_Err_Invalid_Composite : return "invalid composite glyph";
00097 case FT_Err_Too_Many_Hints : return "too many hints";
00098 case FT_Err_Invalid_Pixel_Size : return "invalid pixel size";
00099
00100
00101 case FT_Err_Invalid_Handle : return "invalid object handle";
00102 case FT_Err_Invalid_Library_Handle : return "invalid library handle";
00103 case FT_Err_Invalid_Driver_Handle : return "invalid module handle";
00104 case FT_Err_Invalid_Face_Handle : return "invalid face handle";
00105 case FT_Err_Invalid_Size_Handle : return "invalid size handle";
00106 case FT_Err_Invalid_Slot_Handle : return "invalid glyph slot handle";
00107 case FT_Err_Invalid_CharMap_Handle : return "invalid charmap handle";
00108 case FT_Err_Invalid_Cache_Handle : return "invalid cache manager handle";
00109 case FT_Err_Invalid_Stream_Handle : return "invalid stream handle";
00110
00111
00112 case FT_Err_Too_Many_Drivers : return "too many modules";
00113 case FT_Err_Too_Many_Extensions : return "too many extensions";
00114
00115
00116 case FT_Err_Out_Of_Memory : return "out of memory";
00117 case FT_Err_Unlisted_Object : return "unlisted object";
00118
00119
00120 case FT_Err_Cannot_Open_Stream : return "cannot open stream";
00121 case FT_Err_Invalid_Stream_Seek : return "invalid stream seek";
00122 case FT_Err_Invalid_Stream_Skip : return "invalid stream skip";
00123 case FT_Err_Invalid_Stream_Read : return "invalid stream read";
00124 case FT_Err_Invalid_Stream_Operation : return "invalid stream operation";
00125 case FT_Err_Invalid_Frame_Operation : return "invalid frame operation";
00126 case FT_Err_Nested_Frame_Access : return "nested frame access";
00127 case FT_Err_Invalid_Frame_Read : return "invalid frame read";
00128
00129
00130 case FT_Err_Raster_Uninitialized : return "raster uninitialized";
00131 case FT_Err_Raster_Corrupted : return "raster corrupted";
00132 case FT_Err_Raster_Overflow : return "raster overflow";
00133 case FT_Err_Raster_Negative_Height : return "negative height while rastering";
00134
00135
00136 case FT_Err_Too_Many_Caches : return "too many registered caches";
00137
00138
00139 case FT_Err_Invalid_Opcode : return "invalid opcode";
00140 case FT_Err_Too_Few_Arguments : return "too few arguments";
00141 case FT_Err_Stack_Overflow : return "stack overflow";
00142 case FT_Err_Code_Overflow : return "code overflow";
00143 case FT_Err_Bad_Argument : return "bad argument";
00144 case FT_Err_Divide_By_Zero : return "division by zero";
00145 case FT_Err_Invalid_Reference : return "invalid reference";
00146 case FT_Err_Debug_OpCode : return "found debug opcode";
00147 case FT_Err_ENDF_In_Exec_Stream : return "found ENDF opcode in execution stream";
00148 case FT_Err_Nested_DEFS : return "nested DEFS";
00149 case FT_Err_Invalid_CodeRange : return "invalid code range";
00150 case FT_Err_Execution_Too_Long : return "execution context too long";
00151 case FT_Err_Too_Many_Function_Defs : return "too many function definitions";
00152 case FT_Err_Too_Many_Instruction_Defs : return "too many instruction definitions";
00153 case FT_Err_Table_Missing : return "SFNT font table missing";
00154 case FT_Err_Horiz_Header_Missing : return "horizontal header (hhea) table missing";
00155 case FT_Err_Locations_Missing : return "locations (loca) table missing";
00156 case FT_Err_Name_Table_Missing : return "name table missing";
00157 case FT_Err_CMap_Table_Missing : return "character map (cmap) table missing";
00158 case FT_Err_Hmtx_Table_Missing : return "horizontal metrics (hmtx) table missing";
00159 case FT_Err_Post_Table_Missing : return "PostScript (post) table missing";
00160 case FT_Err_Invalid_Horiz_Metrics : return "invalid horizontal metrics";
00161 case FT_Err_Invalid_CharMap_Format : return "invalid character map (cmap) format";
00162 case FT_Err_Invalid_PPem : return "invalid ppem value";
00163 case FT_Err_Invalid_Vert_Metrics : return "invalid vertical metrics";
00164 case FT_Err_Could_Not_Find_Context : return "could not find context";
00165 case FT_Err_Invalid_Post_Table_Format : return "invalid PostScript (post) table format";
00166 case FT_Err_Invalid_Post_Table : return "invalid PostScript (post) table";
00167
00168
00169 case FT_Err_Syntax_Error : return "opcode syntax error";
00170 case FT_Err_Stack_Underflow : return "argument stack underflow";
00171 case FT_Err_Ignore : return "ignore";
00172
00173
00174 case FT_Err_Missing_Startfont_Field : return "`STARTFONT' field missing";
00175 case FT_Err_Missing_Font_Field : return "`FONT' field missing";
00176 case FT_Err_Missing_Size_Field : return "`SIZE' field missing";
00177 case FT_Err_Missing_Chars_Field : return "`CHARS' field missing";
00178 case FT_Err_Missing_Startchar_Field : return "`STARTCHAR' field missing";
00179 case FT_Err_Missing_Encoding_Field : return "`ENCODING' field missing";
00180 case FT_Err_Missing_Bbx_Field : return "`BBX' field missing";
00181 }
00182
00183 return "";
00184 }
00185 }
00186
00187
00188 namespace sf
00189 {
00190 namespace priv
00191 {
00192
00193 #include <SFML/Graphics/DefaultFont.hpp>
00194
00198 FontManager& FontManager::GetInstance()
00199 {
00200 static FontManager Instance;
00201
00202 return Instance;
00203 }
00204
00205
00209 FontManager::FontManager()
00210 {
00211
00212 FT_Error Error = FT_Init_FreeType(&Library);
00213 if (Error)
00214 {
00215 std::cerr << "Failed to initialize FreeType library (error code : " << Error << ")" << std::endl;
00216 return;
00217 }
00218
00219
00220 CreateDefaultFont();
00221 }
00222
00223
00227 FontManager::~FontManager()
00228 {
00229
00230 if (Library)
00231 FT_Done_FreeType(Library);
00232 }
00233
00234
00238 const FontManager::Font& FontManager::GetBitmapFont(const std::string& Filename, unsigned int CharSize, std::wstring Charset)
00239 {
00240
00241 if (!Library)
00242 return myFonts["default"];
00243
00244
00245 if ((Filename == "") || (Filename == "default"))
00246 return myFonts["default"];
00247
00248
00249 FontTable::iterator It = myFonts.find(Filename);
00250 if ((It != myFonts.end()) && (It->second.CharSize >= CharSize))
00251 return It->second;
00252
00253
00254 int MaxSize = OpenGLCaps::GetMaxTextureSize();
00255 if (static_cast<int>(CharSize) >= MaxSize / 8) CharSize = MaxSize / 8;
00256
00257 unsigned int Left = 0;
00258 unsigned int Top = 0;
00259 unsigned int TexWidth = Image::GetValidTextureSize(CharSize * 8);
00260 unsigned int TexHeight = Image::GetValidTextureSize(CharSize * 8);
00261 std::vector<unsigned int> Tops(TexWidth, 0);
00262
00263
00264 Font CurFont;
00265 CurFont.CharSize = CharSize;
00266 CurFont.Texture.Create(TexWidth, TexHeight, Color(0, 0, 0, 0));
00267
00268
00269 FT_Face FontFace;
00270 FT_Error Error = FT_New_Face(Library, Filename.c_str(), 0, &FontFace);
00271 if (Error)
00272 {
00273 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00274 return myFonts["default"];
00275 }
00276
00277
00278 Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
00279 if (Error)
00280 {
00281 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00282 return myFonts["default"];
00283 }
00284
00285
00286 Error = FT_Select_Charmap(FontFace, FT_ENCODING_UNICODE);
00287 if (Error)
00288 {
00289 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00290 return myFonts["default"];
00291 }
00292
00293
00294 if (Charset.empty())
00295 Charset = DefaultCharset;
00296
00297
00298 Charset += L" \n\v\t";
00299
00300
00301 std::map<wchar_t, IntRect> Coords;
00302 for (std::size_t i = 0; i < Charset.size(); ++i)
00303 {
00304
00305 wchar_t c = Charset[i];
00306 Font::Character& CurChar = CurFont.Characters[c];
00307
00308
00309 Error = FT_Load_Char(FontFace, c, FT_LOAD_DEFAULT);
00310 if (Error)
00311 {
00312 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00313 return myFonts["default"];
00314 }
00315
00316
00317 FT_Glyph Glyph;
00318 Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
00319 if (Error)
00320 {
00321 std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00322 return myFonts["default"];
00323 }
00324 FT_Glyph_To_Bitmap(&Glyph, ft_render_mode_normal, 0, 1);
00325 FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
00326 FT_Bitmap& Bitmap = BitmapGlyph->bitmap;
00327
00328
00329 if (Bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
00330 {
00331 std::cerr << "Error loading font \"" << Filename << "\" (pixel format not supported)" << std::endl;
00332 return myFonts["default"];
00333 }
00334
00335
00336 if (Left + Bitmap.width >= TexWidth)
00337 Left = 0;
00338
00339
00340 Top = Tops[Left];
00341 for (int x = 0; x < Bitmap.width; ++x)
00342 Top = std::max(Top, Tops[Left + x]);
00343
00344
00345 if (Top + Bitmap.rows >= TexHeight)
00346 {
00347 TexHeight *= 2;
00348 CurFont.Texture.Resize(TexWidth, TexHeight, Color(0, 0, 0, 0));
00349 }
00350
00351
00352 CurChar.Rect.Left = BitmapGlyph->left;
00353 CurChar.Rect.Top = -BitmapGlyph->top;
00354 CurChar.Rect.Right = CurChar.Rect.Left + Bitmap.width;
00355 CurChar.Rect.Bottom = Bitmap.rows - BitmapGlyph->top;
00356 CurChar.Advance = FontFace->glyph->advance.x / 64;
00357
00358
00359 Coords[c] = IntRect(Left, Top, Left + Bitmap.width, Top + Bitmap.rows);
00360
00361
00362 const Uint8* Pixels = Bitmap.buffer;
00363 for (int y = 0; y < Bitmap.rows; ++y)
00364 {
00365 for (int x = 0; x < Bitmap.width; ++x)
00366 {
00367 CurFont.Texture.SetPixel(x + Left, y + Top, Color(Pixels[x], Pixels[x], Pixels[x], Pixels[x]));
00368 }
00369 Pixels += Bitmap.pitch;
00370 }
00371
00372 for (int x = 0; x < Bitmap.width; ++x)
00373 Tops[Left + x] = Top + Bitmap.rows;
00374
00375 Left += Bitmap.width;
00376 }
00377
00378
00379 for (std::size_t i = 0; i < Charset.size(); ++i)
00380 {
00381 wchar_t c = Charset[i];
00382 CurFont.Characters[c].Coord = CurFont.Texture.GetTexCoords(Coords[c]);
00383 }
00384
00385
00386 CurFont.Texture.Update();
00387
00388
00389 myFonts[Filename] = CurFont;
00390
00391 return myFonts[Filename];
00392 }
00393
00394
00398 void FontManager::CreateDefaultFont()
00399 {
00400 Font DefaultFont;
00401
00402
00403 DefaultFont.Texture.Create(256, 512);
00404 for (int j = 0; j < 512; ++j)
00405 for (int i = 0; i < 256; ++i)
00406 {
00407 Uint8 Lum = DefaultFontBitmap[i + j * 256];
00408 DefaultFont.Texture.SetPixel(i, j, Color(Lum, Lum, Lum, Lum));
00409 }
00410 DefaultFont.Texture.Update();
00411
00412
00413 for (wchar_t i = 0; i < 256; i++)
00414 {
00415 DefaultFont.Characters[i].Rect = IntRect(DefaultFontRect[i * 4 + 0],
00416 DefaultFontRect[i * 4 + 1],
00417 DefaultFontRect[i * 4 + 2],
00418 DefaultFontRect[i * 4 + 3]);
00419 }
00420
00421
00422 for (wchar_t i = 0; i < 256; i++)
00423 {
00424 DefaultFont.Characters[i].Coord = FloatRect(DefaultFontCoord[i * 4 + 0],
00425 DefaultFontCoord[i * 4 + 1],
00426 DefaultFontCoord[i * 4 + 2],
00427 DefaultFontCoord[i * 4 + 3]);
00428 }
00429
00430
00431 for (wchar_t i = 0; i < 256; i++)
00432 DefaultFont.Characters[i].Advance = DefaultFontAdvance[i];
00433
00434
00435 DefaultFont.CharSize = DefaultFontCharSize;
00436
00437
00438 myFonts.insert(FontTable::value_type("default", DefaultFont));
00439 }
00440
00441 }
00442
00443 }
00444