FontManager.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
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             // Generic errors
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             // Glyph / character errors
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             // Handle errors
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             // Driver errors
00112             case FT_Err_Too_Many_Drivers :          return "too many modules";
00113             case FT_Err_Too_Many_Extensions :       return "too many extensions";
00114 
00115             // Memory errors
00116             case FT_Err_Out_Of_Memory :             return "out of memory";
00117             case FT_Err_Unlisted_Object :           return "unlisted object";
00118 
00119             // Stream errors
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             // Raster errors
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             // Cache errors
00136             case FT_Err_Too_Many_Caches :           return "too many registered caches";
00137 
00138             // TrueType and SFNT errors
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             // CCF, CID and Type 1 errors
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             // BDF errors
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 // Default font bitmap and description are stored in a header file as a sequence of arrays
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     // Initialize FreeType library
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     // Create the default font
00220     CreateDefaultFont();
00221 }
00222 
00223 
00227 FontManager::~FontManager()
00228 {
00229     // Shutdown FreeType library
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     // Check if freetype library is correctly initialized
00241     if (!Library)
00242         return myFonts["default"];
00243 
00244     // If font is "default" or empty string, return default font
00245     if ((Filename == "") || (Filename == "default"))
00246         return myFonts["default"];
00247 
00248     // If font is already loaded and char size is big enough, just return it
00249     FontTable::iterator It = myFonts.find(Filename);
00250     if ((It != myFonts.end()) && (It->second.CharSize >= CharSize))
00251         return It->second;
00252 
00253     // Clamp CharSize to make sure we won't have textures too big
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     // If font name has not been found, we create a new font description
00264     Font CurFont;
00265     CurFont.CharSize = CharSize;
00266     CurFont.Texture.Create(TexWidth, TexHeight, Color(0, 0, 0, 0));
00267 
00268     // Create a new font face from specified file
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     // Setup font size
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     // Select the unicode character map
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     // If no characters set has been provided, we take the default one (31 - 255 ASCII codes)
00294     if (Charset.empty())
00295         Charset = DefaultCharset;
00296 
00297     // Always add these special characters
00298     Charset += L" \n\v\t";
00299 
00300     // Render characters set to a bitmap (printable characters start at code 31)
00301     std::map<wchar_t, IntRect> Coords;
00302     for (std::size_t i = 0; i < Charset.size(); ++i)
00303     {
00304         // Get the current character to generate
00305         wchar_t c = Charset[i];
00306         Font::Character& CurChar = CurFont.Characters[c];
00307 
00308         // Load the glyph corresponding to the current character
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         // Convert the glyph to a bitmap
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         // TODO : handle other pixel modes
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         // Make sure we don't go over the texture width
00336         if (Left + Bitmap.width >= TexWidth)
00337             Left = 0;
00338 
00339         // Compute the top coordinate
00340         Top = Tops[Left];
00341         for (int x = 0; x < Bitmap.width; ++x)
00342             Top = std::max(Top, Tops[Left + x]);
00343 
00344         // Make sure we don't go over the texture height
00345         if (Top + Bitmap.rows >= TexHeight)
00346         {
00347             TexHeight *= 2;
00348             CurFont.Texture.Resize(TexWidth, TexHeight, Color(0, 0, 0, 0));
00349         }
00350 
00351         // Store the character's position and size
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         // Texture size may change, so let the texture coordinates be calculated later
00359         Coords[c] = IntRect(Left, Top, Left + Bitmap.width, Top + Bitmap.rows);
00360 
00361         // Draw the glyph into our bitmap font
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     // Now that the texture has its final size, we can precompute texture coordinates
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     // Update image after modifications
00386     CurFont.Texture.Update();
00387 
00388     // Insert new font
00389     myFonts[Filename] = CurFont;
00390 
00391     return myFonts[Filename];
00392 }
00393 
00394 
00398 void FontManager::CreateDefaultFont()
00399 {
00400     Font DefaultFont;
00401 
00402     // Load bitmap
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     // Load positions
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     // Load texture coordinates
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     // Load advances
00431     for (wchar_t i = 0; i < 256; i++)
00432         DefaultFont.Characters[i].Advance = DefaultFontAdvance[i];
00433 
00434     // Load character size
00435     DefaultFont.CharSize = DefaultFontCharSize;
00436 
00437     // Insert font in font table
00438     myFonts.insert(FontTable::value_type("default", DefaultFont));
00439 }
00440 
00441 } // namespace priv
00442 
00443 } // namespace sf
00444