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