- Main Page
- Namespaces
- Classes
- Files

- File List

# FontLoader.cpp

    00001
    00002 //
    00003 // SFML - Simple and Fast Multimedia Library
    00004 // Copyright (C) 2007-2009 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/FontLoader.hpp>
    00029 #include <SFML/Graphics/Color.hpp>
    00030 #include <SFML/Graphics/Font.hpp>
    00031 #include <SFML/Graphics/Image.hpp>
    00032 #include <SFML/Graphics/GraphicsContext.hpp>
    00033 #include FT_GLYPH_H
    00034 #include <iostream>
    00035 #include <map>
    00036 #include <vector>
    00037 #include <math.h>
    00038
    00039
    00040 namespace
    00041 {
    00043     // Functor to sort glyphs by size
    00045     struct SizeCompare
    00046     {
    00047         bool operator ()(FT_BitmapGlyph Glyph1, FT_BitmapGlyph Glyph2) const
    00048         {
    00049             return Glyph2->bitmap.rows < Glyph1->bitmap.rows;
    00050         }
    00051     };
    00052 }
    00053
    00054 namespace sf
    00055 {
    00056 namespace priv
    00057 {
    00061 FontLoader& FontLoader::GetInstance()
    00062 {
    00063     static FontLoader Instance;
    00064
    00065     return Instance;
    00066 }
    00067
    00068
    00072 FontLoader::FontLoader()
    00073 {
    00074     // Initialize FreeType library
    00075     FT_Error Error = FT_Init_FreeType(&myLibrary);
    00076     if (Error)
    00077     {
    00078         std::cerr << "Failed to initialize FreeType library (error code : " << Error << ")" << std::endl;
    00079         return;
    00080     }
    00081 }
    00082
    00083
    00087 FontLoader::~FontLoader()
    00088 {
    00089     // Shutdown FreeType library
    00090     if (myLibrary)
    00091         FT_Done_FreeType(myLibrary);
    00092 }
    00093
    00094
    00098 bool FontLoader::LoadFontFromFile(const std::string& Filename, unsigned int CharSize, const Unicode::UTF32String& Charset, Font& LoadedFont)
    00099 {
    00100     // Check if Freetype is correctly initialized
    00101     if (!myLibrary)
    00102     {
    00103         std::cerr << "Failed to load font \"" << Filename << "\", FreeType has not been initialized" << std::endl;
    00104         return false;
    00105     }
    00106
    00107     // Create a new font face from the specified file
    00108     FT_Face FontFace;
    00109     FT_Error Error = FT_New_Face(myLibrary, Filename.c_str(), 0, &FontFace);
    00110     if (Error)
    00111     {
    00112         std::cerr << "Failed to load font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
    00113         return false;
    00114     }
    00115
    00116     // Create the bitmap font
    00117     Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
    00118     if (Error)
    00119         std::cerr << "Failed to load font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
    00120
    00121     // Delete the font
    00122     FT_Done_Face(FontFace);
    00123
    00124     return Error == 0;
    00125 }
    00126
    00127
    00131 bool FontLoader::LoadFontFromMemory(const char* Data, std::size_t SizeInBytes, unsigned int CharSize, const Unicode::UTF32String& Charset, Font& LoadedFont)
    00132 {
    00133     // Check if Freetype is correctly initialized
    00134     if (!myLibrary)
    00135     {
    00136         std::cerr << "Failed to load font from memory, FreeType has not been initialized" << std::endl;
    00137         return false;
    00138     }
    00139
    00140     // Create a new font face from the specified memory data
    00141     FT_Face FontFace;
    00142     FT_Error Error = FT_New_Memory_Face(myLibrary, reinterpret_cast<const FT_Byte*>(Data), static_cast<FT_Long>(SizeInBytes), 0, &FontFace);
    00143     if (Error)
    00144     {
    00145         std::cerr << "Failed to load font from memory (" << GetErrorDesc(Error) << ")" << std::endl;
    00146         return false;
    00147     }
    00148
    00149     // Create the bitmap font
    00150     Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
    00151     if (Error)
    00152         std::cerr << "Failed to load font from memory (" << GetErrorDesc(Error) << ")" << std::endl;
    00153
    00154     // Delete the font
    00155     FT_Done_Face(FontFace);
    00156
    00157     return Error == 0;
    00158 }
    00159
    00160
    00164 FT_Error FontLoader::CreateBitmapFont(FT_Face FontFace, unsigned int CharSize, const Unicode::UTF32String& Charset, Font& LoadedFont)
    00165 {
    00166     // Make sure we have a valid context
    00167     priv::GraphicsContext Ctx;
    00168
    00169     // Let's find how many characters to put in each row to make them fit into a squared texture
    00170     GLint MaxSize;
    00171     GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxSize));
    00172     int NbChars = static_cast<int>(sqrt(static_cast<double>(Charset.length())) * 0.75);
    00173
    00174     // Clamp the character size to make sure we won't create a texture too big
    00175     if (NbChars * CharSize >= static_cast<unsigned int>(MaxSize))
    00176         CharSize = MaxSize / NbChars;
    00177
    00178     // Initialize the dimensions
    00179     unsigned int Left      = 0;
    00180     unsigned int Top       = 0;
    00181     unsigned int TexWidth  = Image::GetValidTextureSize(CharSize * NbChars);
    00182     unsigned int TexHeight = CharSize * NbChars;
    00183     std::vector<unsigned int> Tops(TexWidth, 0);
    00184
    00185     // Create a pixel buffer for rendering every glyph
    00186     std::vector<Uint8> GlyphsBuffer(TexWidth * TexHeight * 4);
    00187
    00188     // Setup the font size
    00189     FT_Error Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
    00190     if (Error)
    00191         return Error;
    00192
    00193     // Select the unicode character map
    00194     Error = FT_Select_Charmap(FontFace, FT_ENCODING_UNICODE);
    00195     if (Error)
    00196         return Error;
    00197
    00198     // Render all glyphs and sort them by size to optimize texture space
    00199     typedef std::multimap<FT_BitmapGlyph, Uint32, SizeCompare> GlyphTable;
    00200     GlyphTable Glyphs;
    00201     for (std::size_t i = 0; i < Charset.length(); ++i)
    00202     {
    00203         // Load the glyph corresponding to the current character
    00204         Error = FT_Load_Char(FontFace, Charset[i], FT_LOAD_TARGET_NORMAL);
    00205         if (Error)
    00206             return Error;
    00207
    00208         // Convert the glyph to a bitmap (ie. rasterize it)
    00209         FT_Glyph Glyph;
    00210         Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
    00211         if (Error)
    00212             return Error;
    00213         FT_Glyph_To_Bitmap(&Glyph, FT_RENDER_MODE_NORMAL, 0, 1);
    00214         FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
    00215
    00216         // Should we handle other pixel modes ?
    00217         if (BitmapGlyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
    00218             return FT_Err_Cannot_Render_Glyph;
    00219
    00220         // Add it to the sorted table of glyphs
    00221         Glyphs.insert(std::make_pair(BitmapGlyph, Charset[i]));
    00222     }
    00223
    00224     // Copy the rendered glyphs into the texture
    00225     unsigned int MaxHeight = 0;
    00226     std::map<Uint32, IntRect> Coords;
    00227     for (GlyphTable::const_iterator i = Glyphs.begin(); i != Glyphs.end(); ++i)
    00228     {
    00229         // Get the bitmap of the current glyph
    00230         Glyph&         CurGlyph    = LoadedFont.myGlyphs[i->second];
    00231         FT_BitmapGlyph BitmapGlyph = i->first;
    00232         FT_Bitmap&     Bitmap      = BitmapGlyph->bitmap;
    00233
    00234         // Make sure we don't go over the texture width
    00235         if (Left + Bitmap.width + 1 >= TexWidth)
    00236             Left = 0;
    00237
    00238         // Compute the top coordinate
    00239         Top = Tops[Left];
    00240         for (int x = 0; x < Bitmap.width + 1; ++x)
    00241             Top = std::max(Top, Tops[Left + x]);
    00242         Top++;
    00243
    00244         // Make sure we don't go over the texture height -- resize it if we need more space
    00245         if (Top + Bitmap.rows + 1 >= TexHeight)
    00246         {
    00247             TexHeight *= 2;
    00248             GlyphsBuffer.resize(TexWidth * TexHeight * 4);
    00249         }
    00250
    00251         // Store the character's position and size
    00252         CurGlyph.Rectangle.Left   = BitmapGlyph->left;
    00253         CurGlyph.Rectangle.Top    = -BitmapGlyph->top;
    00254         CurGlyph.Rectangle.Right  = CurGlyph.Rectangle.Left + Bitmap.width;
    00255         CurGlyph.Rectangle.Bottom = Bitmap.rows - BitmapGlyph->top;
    00256         CurGlyph.Advance          = BitmapGlyph->root.advance.x >> 16;
    00257
    00258         // Texture size may change, so let the texture coordinates be calculated later
    00259         Coords[i->second] = IntRect(Left + 1, Top + 1, Left + Bitmap.width + 1, Top + Bitmap.rows + 1);
    00260
    00261         // Draw the glyph into our bitmap font
    00262         const Uint8* Pixels = Bitmap.buffer;
    00263         for (int y = 0; y < Bitmap.rows; ++y)
    00264         {
    00265             for (int x = 0; x < Bitmap.width; ++x)
    00266             {
    00267                 std::size_t Index = x + Left + 1 + (y + Top + 1) * TexWidth;
    00268                 GlyphsBuffer[Index * 4 + 0] = 255;
    00269                 GlyphsBuffer[Index * 4 + 1] = 255;
    00270                 GlyphsBuffer[Index * 4 + 2] = 255;
    00271                 GlyphsBuffer[Index * 4 + 3] = Pixels[x];
    00272             }
    00273             Pixels += Bitmap.pitch;
    00274         }
    00275
    00276         // Update the rendering coordinates
    00277         for (int x = 0; x < Bitmap.width + 1; ++x)
    00278             Tops[Left + x] = Top + Bitmap.rows;
    00279         Left += Bitmap.width + 1;
    00280         if (Top + Bitmap.rows > MaxHeight)
    00281             MaxHeight = Top + Bitmap.rows;
    00282
    00283         // Delete the glyph
    00284         FT_Done_Glyph((FT_Glyph)BitmapGlyph);
    00285     }
    00286
    00287     // Create the font's texture
    00288     TexHeight = MaxHeight + 1;
    00289     GlyphsBuffer.resize(TexWidth * TexHeight * 4);
    00290     LoadedFont.myTexture.LoadFromPixels(TexWidth, TexHeight, &GlyphsBuffer[0]);
    00291
    00292     // Now that the texture is created, we can precompute texture coordinates
    00293     for (std::size_t i = 0; i < Charset.size(); ++i)
    00294     {
    00295         Uint32 CurChar = Charset[i];
    00296         LoadedFont.myGlyphs[CurChar].TexCoords = LoadedFont.myTexture.GetTexCoords(Coords[CurChar], false);
    00297     }
    00298
    00299     // Update the character size (it may have been changed by the function)
    00300     LoadedFont.myCharSize = CharSize;
    00301
    00302     return 0;
    00303 }
    00304
    00305
    00309 std::string FontLoader::GetErrorDesc(FT_Error Error)
    00310 {
    00311     switch (Error)
    00312     {
    00313         // Generic errors
    00314         case FT_Err_Cannot_Open_Resource :      return "cannot open resource";
    00315         case FT_Err_Unknown_File_Format :       return "unknown file format";
    00316         case FT_Err_Invalid_File_Format :       return "broken file";
    00317         case FT_Err_Invalid_Version :           return "invalid FreeType version";
    00318         case FT_Err_Lower_Module_Version :      return "module version is too low";
    00319         case FT_Err_Invalid_Argument :          return "invalid argument";
    00320         case FT_Err_Unimplemented_Feature :     return "unimplemented feature";
    00321         case FT_Err_Invalid_Table :             return "broken table";
    00322         case FT_Err_Invalid_Offset :            return "broken offset within table";
    00323
    00324         // Glyph / character errors
    00325         case FT_Err_Invalid_Glyph_Index :       return "invalid glyph index";
    00326         case FT_Err_Invalid_Character_Code :    return "invalid character code";
    00327         case FT_Err_Invalid_Glyph_Format :      return "unsupported glyph image format";
    00328         case FT_Err_Cannot_Render_Glyph :       return "cannot render this glyph format";
    00329         case FT_Err_Invalid_Outline :           return "invalid outline";
    00330         case FT_Err_Invalid_Composite :         return "invalid composite glyph";
    00331         case FT_Err_Too_Many_Hints :            return "too many hints";
    00332         case FT_Err_Invalid_Pixel_Size :        return "invalid pixel size";
    00333
    00334         // Handle errors
    00335         case FT_Err_Invalid_Handle :            return "invalid object handle";
    00336         case FT_Err_Invalid_Library_Handle :    return "invalid library handle";
    00337         case FT_Err_Invalid_Driver_Handle :     return "invalid module handle";
    00338         case FT_Err_Invalid_Face_Handle :       return "invalid face handle";
    00339         case FT_Err_Invalid_Size_Handle :       return "invalid size handle";
    00340         case FT_Err_Invalid_Slot_Handle :       return "invalid glyph slot handle";
    00341         case FT_Err_Invalid_CharMap_Handle :    return "invalid charmap handle";
    00342         case FT_Err_Invalid_Cache_Handle :      return "invalid cache manager handle";
    00343         case FT_Err_Invalid_Stream_Handle :     return "invalid stream handle";
    00344
    00345         // Driver errors
    00346         case FT_Err_Too_Many_Drivers :          return "too many modules";
    00347         case FT_Err_Too_Many_Extensions :       return "too many extensions";
    00348
    00349         // Memory errors
    00350         case FT_Err_Out_Of_Memory :             return "out of memory";
    00351         case FT_Err_Unlisted_Object :           return "unlisted object";
    00352
    00353         // Stream errors
    00354         case FT_Err_Cannot_Open_Stream :        return "cannot open stream";
    00355         case FT_Err_Invalid_Stream_Seek :       return "invalid stream seek";
    00356         case FT_Err_Invalid_Stream_Skip :       return "invalid stream skip";
    00357         case FT_Err_Invalid_Stream_Read :       return "invalid stream read";
    00358         case FT_Err_Invalid_Stream_Operation :  return "invalid stream operation";
    00359         case FT_Err_Invalid_Frame_Operation :   return "invalid frame operation";
    00360         case FT_Err_Nested_Frame_Access :       return "nested frame access";
    00361         case FT_Err_Invalid_Frame_Read :        return "invalid frame read";
    00362
    00363         // Raster errors
    00364         case FT_Err_Raster_Uninitialized :      return "raster uninitialized";
    00365         case FT_Err_Raster_Corrupted :          return "raster corrupted";
    00366         case FT_Err_Raster_Overflow :           return "raster overflow";
    00367         case FT_Err_Raster_Negative_Height :    return "negative height while rastering";
    00368
    00369         // Cache errors
    00370         case FT_Err_Too_Many_Caches :           return "too many registered caches";
    00371
    00372         // TrueType and SFNT errors
    00373         case FT_Err_Invalid_Opcode :            return "invalid opcode";
    00374         case FT_Err_Too_Few_Arguments :         return "too few arguments";
    00375         case FT_Err_Stack_Overflow :            return "stack overflow";
    00376         case FT_Err_Code_Overflow :             return "code overflow";
    00377         case FT_Err_Bad_Argument :              return "bad argument";
    00378         case FT_Err_Divide_By_Zero :            return "division by zero";
    00379         case FT_Err_Invalid_Reference :         return "invalid reference";
    00380         case FT_Err_Debug_OpCode :              return "found debug opcode";
    00381         case FT_Err_ENDF_In_Exec_Stream :       return "found ENDF opcode in execution stream";
    00382         case FT_Err_Nested_DEFS :               return "nested DEFS";
    00383         case FT_Err_Invalid_CodeRange :         return "invalid code range";
    00384         case FT_Err_Execution_Too_Long :        return "execution context too long";
    00385         case FT_Err_Too_Many_Function_Defs :    return "too many function definitions";
    00386         case FT_Err_Too_Many_Instruction_Defs : return "too many instruction definitions";
    00387         case FT_Err_Table_Missing :             return "SFNT font table missing";
    00388         case FT_Err_Horiz_Header_Missing :      return "horizontal header (hhea) table missing";
    00389         case FT_Err_Locations_Missing :         return "locations (loca) table missing";
    00390         case FT_Err_Name_Table_Missing :        return "name table missing";
    00391         case FT_Err_CMap_Table_Missing :        return "character map (cmap) table missing";
    00392         case FT_Err_Hmtx_Table_Missing :        return "horizontal metrics (hmtx) table missing";
    00393         case FT_Err_Post_Table_Missing :        return "PostScript (post) table missing";
    00394         case FT_Err_Invalid_Horiz_Metrics :     return "invalid horizontal metrics";
    00395         case FT_Err_Invalid_CharMap_Format :    return "invalid character map (cmap) format";
    00396         case FT_Err_Invalid_PPem :              return "invalid ppem value";
    00397         case FT_Err_Invalid_Vert_Metrics :      return "invalid vertical metrics";
    00398         case FT_Err_Could_Not_Find_Context :    return "could not find context";
    00399         case FT_Err_Invalid_Post_Table_Format : return "invalid PostScript (post) table format";
    00400         case FT_Err_Invalid_Post_Table :        return "invalid PostScript (post) table";
    00401
    00402         // CCF, CID and Type 1 errors
    00403         case FT_Err_Syntax_Error :              return "opcode syntax error";
    00404         case FT_Err_Stack_Underflow :           return "argument stack underflow";
    00405         case FT_Err_Ignore :                    return "ignore";
    00406
    00407         // BDF errors
    00408         case FT_Err_Missing_Startfont_Field :   return "`STARTFONT' field missing";
    00409         case FT_Err_Missing_Font_Field :        return "`FONT' field missing";
    00410         case FT_Err_Missing_Size_Field :        return "`SIZE' field missing";
    00411         case FT_Err_Missing_Chars_Field :       return "`CHARS' field missing";
    00412         case FT_Err_Missing_Startchar_Field :   return "`STARTCHAR' field missing";
    00413         case FT_Err_Missing_Encoding_Field :    return "`ENCODING' field missing";
    00414         case FT_Err_Missing_Bbx_Field :         return "`BBX' field missing";
    00415     }
    00416
    00417     return "unknown error";
    00418 }
    00419
    00420 } // namespace priv
    00421
    00422 } // namespace sf
    00423

:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::