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 <iostream>
00034 #include <vector>
00035 
00036 
00037 namespace sf_private
00038 {
00039 // Default font bitmap and description are stored in a header file as a sequence of arrays
00040 #include <SFML/Graphics/DefaultFont.hpp>
00041 
00042 
00046 sfFontManager& sfFontManager::GetInstance()
00047 {
00048     static sfFontManager Instance;
00049 
00050     return Instance;
00051 }
00052 
00053 
00057 sfFontManager::sfFontManager() :
00058 myLibrary(NULL)
00059 {
00060     // Initialize FreeType library
00061     FT_Error Error = FT_Init_FreeType(&myLibrary);
00062     if (Error)
00063     {
00064         std::cerr << "Failed to initialize FreeType library (error code : " << Error << ")" << std::endl;
00065         return;
00066     }
00067 
00068     // Create the default font
00069     CreateDefaultFont();
00070 }
00071 
00072 
00076 sfFontManager::~sfFontManager()
00077 {
00078     // Shutdown FreeType library
00079     if (myLibrary)
00080         FT_Done_FreeType(myLibrary);
00081 }
00082 
00083 
00087 const sfFontManager::Font& sfFontManager::GetBitmapFont(const std::string& Filename, unsigned int CharSize)
00088 {
00089     // Check if freetype library is correctly initialized
00090     if (!myLibrary)
00091         return myFonts["default"];
00092 
00093     // If font is "default" or empty string, return default font
00094     if ((Filename == "") || (Filename == "default"))
00095         return myFonts["default"];
00096 
00097     // If font is already loaded and char size is big enough, just return it
00098     FontTable::iterator It = myFonts.find(Filename);
00099     if ((It != myFonts.end()) && (It->second.CharSize >= CharSize))
00100         return It->second;
00101 
00102     // Clamp CharSize to make sure we won't have textures too big
00103     int MaxSize = sfOpenGLCaps::GetMaxTextureSize();
00104     if ((int)CharSize >= MaxSize / 8) CharSize = MaxSize / 8;
00105 
00106     unsigned int Left      = 0;
00107     unsigned int Top       = 0;
00108     unsigned int TexWidth  = sfImage::GetValidTextureSize(CharSize * 8);
00109     unsigned int TexHeight = sfImage::GetValidTextureSize(CharSize * 8);
00110     std::vector<unsigned int> Tops(TexWidth, 0);
00111 
00112     // If font name has not been found, we create a new font description
00113     Font CurFont;
00114     CurFont.CharSize = CharSize;
00115     CurFont.Image.Create(TexWidth, TexHeight, sfColor(0, 0, 0, 0));
00116 
00117     // Create a new font face from specified file
00118     FT_Face FontFace;
00119     FT_Error Error = FT_New_Face(myLibrary, Filename.c_str(), 0, &FontFace);
00120     if (Error)
00121     {
00122         std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00123         return myFonts["default"];
00124     }
00125 
00126     // Setup font size
00127     Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
00128     if (Error)
00129     {
00130         std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00131         return myFonts["default"];
00132     }
00133 
00134     // Render characters set to a bitmap (printable characters start at code 31)
00135     sfIntRect Coords[256];
00136     for (int i = 31; i < 256; ++i)
00137     {
00138         // Load the glyph corresponding to the current character
00139         Error = FT_Load_Char(FontFace, i, FT_LOAD_DEFAULT);
00140         if (Error)
00141         {
00142             std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00143             return myFonts["default"];
00144         }
00145 
00146         // Convert the glyph to a bitmap
00147         FT_Glyph Glyph;
00148         Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
00149         if (Error)
00150         {
00151             std::cerr << "Error loading font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
00152             return myFonts["default"];
00153         }
00154         FT_Glyph_To_Bitmap(&Glyph, ft_render_mode_normal, 0, 1);
00155         FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
00156         FT_Bitmap& Bitmap = BitmapGlyph->bitmap;
00157 
00158         // TODO : handle other pixel modes
00159         if (Bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
00160         {
00161             std::cerr << "Error loading font \"" << Filename << "\" (pixel format not supported)" << std::endl;
00162             return myFonts["default"];
00163         }
00164 
00165         // Make sure we don't go over the texture width
00166         if (Left + Bitmap.width >= TexWidth)
00167             Left = 0;
00168 
00169         // Compute the top coordinate
00170         Top = Tops[Left];
00171         for (int x = 0; x < Bitmap.width; ++x)
00172             Top = std::max(Top, Tops[Left + x]);
00173 
00174         // Make sure we don't go over the texture height
00175         if (Top + Bitmap.rows >= TexHeight)
00176         {
00177             TexHeight *= 2;
00178             CurFont.Image.Resize(TexWidth, TexHeight, sfColor(0, 0, 0, 0));
00179         }
00180 
00181         // Store the character's position and size
00182         sfIntRect& Rect = CurFont.Rect[i];
00183         Rect.Left   = BitmapGlyph->left;
00184         Rect.Top    = -BitmapGlyph->top;
00185         Rect.Right  = Rect.Left + Bitmap.width;
00186         Rect.Bottom = Bitmap.rows - BitmapGlyph->top;
00187         CurFont.Advance[i] = FontFace->glyph->advance.x / 64;
00188 
00189         // Texture size may change, so let the texture coordinates be calculated later
00190         Coords[i] = sfIntRect(Left, Top, Left + Bitmap.width, Top + Bitmap.rows);
00191 
00192         // Draw the glyph into our bitmap font
00193         const sfUint8* Pixels = Bitmap.buffer;
00194         for (int y = 0; y < Bitmap.rows; ++y)
00195         {
00196             for (int x = 0; x < Bitmap.width; ++x)
00197             {
00198                 CurFont.Image.SetPixel(x + Left, y + Top, sfColor(Pixels[x], Pixels[x], Pixels[x], Pixels[x]));
00199             }
00200             Pixels += Bitmap.pitch;
00201         }
00202 
00203         for (int x = 0; x < Bitmap.width; ++x)
00204             Tops[Left + x] = Top + Bitmap.rows;
00205 
00206         Left += Bitmap.width;
00207     }
00208 
00209     // Now that the texture has its final size, we can precompute texture coordinates
00210     for (int i = 31; i < 256; ++i)
00211         CurFont.Coord[i] = CurFont.Image.GetTexCoords(Coords[i]);
00212 
00213     // Update image after modifications
00214     CurFont.Image.Update();
00215 
00216     // Insert new font
00217     myFonts[Filename] = CurFont;
00218 
00219     return myFonts[Filename];
00220 }
00221 
00222 
00226 void sfFontManager::CreateDefaultFont()
00227 {
00228     Font DefaultFont;
00229 
00230     // Load bitmap
00231     DefaultFont.Image.Create(256, 512);
00232     for (int j = 0; j < 512; ++j)
00233         for (int i = 0; i < 256; ++i)
00234         {
00235             sfUint8 Lum = DefaultFontBitmap[i + j * 256];
00236             DefaultFont.Image.SetPixel(i, j, sfColor(Lum, Lum, Lum, Lum));
00237         }
00238     DefaultFont.Image.Update();
00239 
00240     // Load positions
00241     for (int i = 0; i < 256; i++)
00242     {
00243         DefaultFont.Rect[i] = sfIntRect(DefaultFontRect[i * 4 + 0],
00244                                         DefaultFontRect[i * 4 + 1],
00245                                         DefaultFontRect[i * 4 + 2],
00246                                         DefaultFontRect[i * 4 + 3]);
00247     }
00248 
00249     // Load texture coordinates
00250     for (int i = 0; i < 256; i++)
00251     {
00252         DefaultFont.Coord[i] = sfFloatRect(DefaultFontCoord[i * 4 + 0],
00253                                            DefaultFontCoord[i * 4 + 1],
00254                                            DefaultFontCoord[i * 4 + 2],
00255                                            DefaultFontCoord[i * 4 + 3]);
00256     }
00257 
00258     // Load advances
00259     for (int i = 0; i < 256; i++)
00260         DefaultFont.Advance[i] = DefaultFontAdvance[i];
00261 
00262     // Load character size
00263     DefaultFont.CharSize = DefaultFontCharSize;
00264 
00265     // Insert font in font table
00266     myFonts.insert(FontTable::value_type("default", DefaultFont));
00267 }
00268 
00269 
00273 std::string sfFontManager::GetErrorDesc(FT_Error Error)
00274 {
00275     switch (Error)
00276     {
00277         // Generic errors
00278         case FT_Err_Cannot_Open_Resource :      return "cannot open resource";
00279         case FT_Err_Unknown_File_Format :       return "unknown file format";
00280         case FT_Err_Invalid_File_Format :       return "broken file";
00281         case FT_Err_Invalid_Version :           return "invalid FreeType version";
00282         case FT_Err_Lower_Module_Version :      return "module version is too low";
00283         case FT_Err_Invalid_Argument :          return "invalid argument";
00284         case FT_Err_Unimplemented_Feature :     return "unimplemented feature";
00285         case FT_Err_Invalid_Table :             return "broken table";
00286         case FT_Err_Invalid_Offset :            return "broken offset within table";
00287 
00288         // Glyph / character errors
00289         case FT_Err_Invalid_Glyph_Index :       return "invalid glyph index";
00290         case FT_Err_Invalid_Character_Code :    return "invalid character code";
00291         case FT_Err_Invalid_Glyph_Format :      return "unsupported glyph image format";
00292         case FT_Err_Cannot_Render_Glyph :       return "cannot render this glyph format";
00293         case FT_Err_Invalid_Outline :           return "invalid outline";
00294         case FT_Err_Invalid_Composite :         return "invalid composite glyph";
00295         case FT_Err_Too_Many_Hints :            return "too many hints";
00296         case FT_Err_Invalid_Pixel_Size :        return "invalid pixel size";
00297 
00298         // Handle errors
00299         case FT_Err_Invalid_Handle :            return "invalid object handle";
00300         case FT_Err_Invalid_Library_Handle :    return "invalid library handle";
00301         case FT_Err_Invalid_Driver_Handle :     return "invalid module handle";
00302         case FT_Err_Invalid_Face_Handle :       return "invalid face handle";
00303         case FT_Err_Invalid_Size_Handle :       return "invalid size handle";
00304         case FT_Err_Invalid_Slot_Handle :       return "invalid glyph slot handle";
00305         case FT_Err_Invalid_CharMap_Handle :    return "invalid charmap handle";
00306         case FT_Err_Invalid_Cache_Handle :      return "invalid cache manager handle";
00307         case FT_Err_Invalid_Stream_Handle :     return "invalid stream handle";
00308 
00309         // Driver errors
00310         case FT_Err_Too_Many_Drivers :          return "too many modules";
00311         case FT_Err_Too_Many_Extensions :       return "too many extensions";
00312 
00313         // Memory errors
00314         case FT_Err_Out_Of_Memory :             return "out of memory";
00315         case FT_Err_Unlisted_Object :           return "unlisted object";
00316 
00317         // Stream errors
00318         case FT_Err_Cannot_Open_Stream :        return "cannot open stream";
00319         case FT_Err_Invalid_Stream_Seek :       return "invalid stream seek";
00320         case FT_Err_Invalid_Stream_Skip :       return "invalid stream skip";
00321         case FT_Err_Invalid_Stream_Read :       return "invalid stream read";
00322         case FT_Err_Invalid_Stream_Operation :  return "invalid stream operation";
00323         case FT_Err_Invalid_Frame_Operation :   return "invalid frame operation";
00324         case FT_Err_Nested_Frame_Access :       return "nested frame access";
00325         case FT_Err_Invalid_Frame_Read :        return "invalid frame read";
00326 
00327         // Raster errors
00328         case FT_Err_Raster_Uninitialized :      return "raster uninitialized";
00329         case FT_Err_Raster_Corrupted :          return "raster corrupted";
00330         case FT_Err_Raster_Overflow :           return "raster overflow";
00331         case FT_Err_Raster_Negative_Height :    return "negative height while rastering";
00332 
00333         // Cache errors
00334         case FT_Err_Too_Many_Caches :           return "too many registered caches";
00335 
00336         // TrueType and SFNT errors
00337         case FT_Err_Invalid_Opcode :            return "invalid opcode";
00338         case FT_Err_Too_Few_Arguments :         return "too few arguments";
00339         case FT_Err_Stack_Overflow :            return "stack overflow";
00340         case FT_Err_Code_Overflow :             return "code overflow";
00341         case FT_Err_Bad_Argument :              return "bad argument";
00342         case FT_Err_Divide_By_Zero :            return "division by zero";
00343         case FT_Err_Invalid_Reference :         return "invalid reference";
00344         case FT_Err_Debug_OpCode :              return "found debug opcode";
00345         case FT_Err_ENDF_In_Exec_Stream :       return "found ENDF opcode in execution stream";
00346         case FT_Err_Nested_DEFS :               return "nested DEFS";
00347         case FT_Err_Invalid_CodeRange :         return "invalid code range";
00348         case FT_Err_Execution_Too_Long :        return "execution context too long";
00349         case FT_Err_Too_Many_Function_Defs :    return "too many function definitions";
00350         case FT_Err_Too_Many_Instruction_Defs : return "too many instruction definitions";
00351         case FT_Err_Table_Missing :             return "SFNT font table missing";
00352         case FT_Err_Horiz_Header_Missing :      return "horizontal header (hhea) table missing";
00353         case FT_Err_Locations_Missing :         return "locations (loca) table missing";
00354         case FT_Err_Name_Table_Missing :        return "name table missing";
00355         case FT_Err_CMap_Table_Missing :        return "character map (cmap) table missing";
00356         case FT_Err_Hmtx_Table_Missing :        return "horizontal metrics (hmtx) table missing";
00357         case FT_Err_Post_Table_Missing :        return "PostScript (post) table missing";
00358         case FT_Err_Invalid_Horiz_Metrics :     return "invalid horizontal metrics";
00359         case FT_Err_Invalid_CharMap_Format :    return "invalid character map (cmap) format";
00360         case FT_Err_Invalid_PPem :              return "invalid ppem value";
00361         case FT_Err_Invalid_Vert_Metrics :      return "invalid vertical metrics";
00362         case FT_Err_Could_Not_Find_Context :    return "could not find context";
00363         case FT_Err_Invalid_Post_Table_Format : return "invalid PostScript (post) table format";
00364         case FT_Err_Invalid_Post_Table :        return "invalid PostScript (post) table";
00365 
00366         // CCF, CID and Type 1 errors
00367         case FT_Err_Syntax_Error :              return "opcode syntax error";
00368         case FT_Err_Stack_Underflow :           return "argument stack underflow";
00369         case FT_Err_Ignore :                    return "ignore";
00370 
00371         // BDF errors
00372         case FT_Err_Missing_Startfont_Field :   return "`STARTFONT' field missing";
00373         case FT_Err_Missing_Font_Field :        return "`FONT' field missing";
00374         case FT_Err_Missing_Size_Field :        return "`SIZE' field missing";
00375         case FT_Err_Missing_Chars_Field :       return "`CHARS' field missing";
00376         case FT_Err_Missing_Startchar_Field :   return "`STARTCHAR' field missing";
00377         case FT_Err_Missing_Encoding_Field :    return "`ENCODING' field missing";
00378         case FT_Err_Missing_Bbx_Field :         return "`BBX' field missing";
00379     }
00380 
00381     return "";
00382 }
00383 
00384 } // namespace sf_private