- 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         // Add it to the sorted table of glyphs
    00217         Glyphs.insert(std::make_pair(BitmapGlyph, Charset[i]));
    00218     }
    00219
    00220     // Copy the rendered glyphs into the texture
    00221     unsigned int MaxHeight = 0;
    00222     std::map<Uint32, IntRect> Coords;
    00223     for (GlyphTable::const_iterator i = Glyphs.begin(); i != Glyphs.end(); ++i)
    00224     {
    00225         // Get the bitmap of the current glyph
    00226         Glyph&         CurGlyph    = LoadedFont.myGlyphs[i->second];
    00227         FT_BitmapGlyph BitmapGlyph = i->first;
    00228         FT_Bitmap&     Bitmap      = BitmapGlyph->bitmap;
    00229
    00230         // Make sure we don't go over the texture width
    00231         if (Left + Bitmap.width + 1 >= TexWidth)
    00232             Left = 0;
    00233
    00234         // Compute the top coordinate
    00235         Top = Tops[Left];
    00236         for (int x = 0; x < Bitmap.width + 1; ++x)
    00237             Top = std::max(Top, Tops[Left + x]);
    00238         Top++;
    00239
    00240         // Make sure we don't go over the texture height -- resize it if we need more space
    00241         if (Top + Bitmap.rows + 1 >= TexHeight)
    00242         {
    00243             TexHeight *= 2;
    00244             GlyphsBuffer.resize(TexWidth * TexHeight * 4);
    00245         }
    00246
    00247         // Store the character's position and size
    00248         CurGlyph.Rectangle.Left   = BitmapGlyph->left;
    00249         CurGlyph.Rectangle.Top    = -BitmapGlyph->top;
    00250         CurGlyph.Rectangle.Right  = CurGlyph.Rectangle.Left + Bitmap.width;
    00251         CurGlyph.Rectangle.Bottom = Bitmap.rows - BitmapGlyph->top;
    00252         CurGlyph.Advance          = BitmapGlyph->root.advance.x >> 16;
    00253
    00254         // Texture size may change, so let the texture coordinates be calculated later
    00255         Coords[i->second] = IntRect(Left + 1, Top + 1, Left + Bitmap.width + 1, Top + Bitmap.rows + 1);
    00256
    00257         // Draw the glyph into our bitmap font
    00258         const Uint8* Pixels = Bitmap.buffer;
    00259         for (int y = 0; y < Bitmap.rows; ++y)
    00260         {
    00261             for (int x = 0; x < Bitmap.width; ++x)
    00262             {
    00263                 std::size_t Index = x + Left + 1 + (y + Top + 1) * TexWidth;
    00264                 GlyphsBuffer[Index * 4 + 0] = 255;
    00265                 GlyphsBuffer[Index * 4 + 1] = 255;
    00266                 GlyphsBuffer[Index * 4 + 2] = 255;
    00267                 GlyphsBuffer[Index * 4 + 3] = Pixels[x];
    00268             }
    00269             Pixels += Bitmap.pitch;
    00270         }
    00271
    00272         // Update the rendering coordinates
    00273         for (int x = 0; x < Bitmap.width + 1; ++x)
    00274             Tops[Left + x] = Top + Bitmap.rows;
    00275         Left += Bitmap.width + 1;
    00276         if (Top + Bitmap.rows > MaxHeight)
    00277             MaxHeight = Top + Bitmap.rows;
    00278
    00279         // Delete the glyph
    00280         FT_Done_Glyph((FT_Glyph)BitmapGlyph);
    00281     }
    00282
    00283     // Create the font's texture
    00284     TexHeight = MaxHeight + 1;
    00285     GlyphsBuffer.resize(TexWidth * TexHeight * 4);
    00286     LoadedFont.myTexture.LoadFromPixels(TexWidth, TexHeight, &GlyphsBuffer[0]);
    00287
    00288     // Now that the texture is created, we can precompute texture coordinates
    00289     for (std::size_t i = 0; i < Charset.size(); ++i)
    00290     {
    00291         Uint32 CurChar = Charset[i];
    00292         LoadedFont.myGlyphs[CurChar].TexCoords = LoadedFont.myTexture.GetTexCoords(Coords[CurChar]);
    00293     }
    00294
    00295     // Update the character size (it may have been changed by the function)
    00296     LoadedFont.myCharSize = CharSize;
    00297
    00298     return 0;
    00299 }
    00300
    00301
    00305 std::string FontLoader::GetErrorDesc(FT_Error Error)
    00306 {
    00307     switch (Error)
    00308     {
    00309         // Generic errors
    00310         case FT_Err_Cannot_Open_Resource :      return "cannot open resource";
    00311         case FT_Err_Unknown_File_Format :       return "unknown file format";
    00312         case FT_Err_Invalid_File_Format :       return "broken file";
    00313         case FT_Err_Invalid_Version :           return "invalid FreeType version";
    00314         case FT_Err_Lower_Module_Version :      return "module version is too low";
    00315         case FT_Err_Invalid_Argument :          return "invalid argument";
    00316         case FT_Err_Unimplemented_Feature :     return "unimplemented feature";
    00317         case FT_Err_Invalid_Table :             return "broken table";
    00318         case FT_Err_Invalid_Offset :            return "broken offset within table";
    00319
    00320         // Glyph / character errors
    00321         case FT_Err_Invalid_Glyph_Index :       return "invalid glyph index";
    00322         case FT_Err_Invalid_Character_Code :    return "invalid character code";
    00323         case FT_Err_Invalid_Glyph_Format :      return "unsupported glyph image format";
    00324         case FT_Err_Cannot_Render_Glyph :       return "cannot render this glyph format";
    00325         case FT_Err_Invalid_Outline :           return "invalid outline";
    00326         case FT_Err_Invalid_Composite :         return "invalid composite glyph";
    00327         case FT_Err_Too_Many_Hints :            return "too many hints";
    00328         case FT_Err_Invalid_Pixel_Size :        return "invalid pixel size";
    00329
    00330         // Handle errors
    00331         case FT_Err_Invalid_Handle :            return "invalid object handle";
    00332         case FT_Err_Invalid_Library_Handle :    return "invalid library handle";
    00333         case FT_Err_Invalid_Driver_Handle :     return "invalid module handle";
    00334         case FT_Err_Invalid_Face_Handle :       return "invalid face handle";
    00335         case FT_Err_Invalid_Size_Handle :       return "invalid size handle";
    00336         case FT_Err_Invalid_Slot_Handle :       return "invalid glyph slot handle";
    00337         case FT_Err_Invalid_CharMap_Handle :    return "invalid charmap handle";
    00338         case FT_Err_Invalid_Cache_Handle :      return "invalid cache manager handle";
    00339         case FT_Err_Invalid_Stream_Handle :     return "invalid stream handle";
    00340
    00341         // Driver errors
    00342         case FT_Err_Too_Many_Drivers :          return "too many modules";
    00343         case FT_Err_Too_Many_Extensions :       return "too many extensions";
    00344
    00345         // Memory errors
    00346         case FT_Err_Out_Of_Memory :             return "out of memory";
    00347         case FT_Err_Unlisted_Object :           return "unlisted object";
    00348
    00349         // Stream errors
    00350         case FT_Err_Cannot_Open_Stream :        return "cannot open stream";
    00351         case FT_Err_Invalid_Stream_Seek :       return "invalid stream seek";
    00352         case FT_Err_Invalid_Stream_Skip :       return "invalid stream skip";
    00353         case FT_Err_Invalid_Stream_Read :       return "invalid stream read";
    00354         case FT_Err_Invalid_Stream_Operation :  return "invalid stream operation";
    00355         case FT_Err_Invalid_Frame_Operation :   return "invalid frame operation";
    00356         case FT_Err_Nested_Frame_Access :       return "nested frame access";
    00357         case FT_Err_Invalid_Frame_Read :        return "invalid frame read";
    00358
    00359         // Raster errors
    00360         case FT_Err_Raster_Uninitialized :      return "raster uninitialized";
    00361         case FT_Err_Raster_Corrupted :          return "raster corrupted";
    00362         case FT_Err_Raster_Overflow :           return "raster overflow";
    00363         case FT_Err_Raster_Negative_Height :    return "negative height while rastering";
    00364
    00365         // Cache errors
    00366         case FT_Err_Too_Many_Caches :           return "too many registered caches";
    00367
    00368         // TrueType and SFNT errors
    00369         case FT_Err_Invalid_Opcode :            return "invalid opcode";
    00370         case FT_Err_Too_Few_Arguments :         return "too few arguments";
    00371         case FT_Err_Stack_Overflow :            return "stack overflow";
    00372         case FT_Err_Code_Overflow :             return "code overflow";
    00373         case FT_Err_Bad_Argument :              return "bad argument";
    00374         case FT_Err_Divide_By_Zero :            return "division by zero";
    00375         case FT_Err_Invalid_Reference :         return "invalid reference";
    00376         case FT_Err_Debug_OpCode :              return "found debug opcode";
    00377         case FT_Err_ENDF_In_Exec_Stream :       return "found ENDF opcode in execution stream";
    00378         case FT_Err_Nested_DEFS :               return "nested DEFS";
    00379         case FT_Err_Invalid_CodeRange :         return "invalid code range";
    00380         case FT_Err_Execution_Too_Long :        return "execution context too long";
    00381         case FT_Err_Too_Many_Function_Defs :    return "too many function definitions";
    00382         case FT_Err_Too_Many_Instruction_Defs : return "too many instruction definitions";
    00383         case FT_Err_Table_Missing :             return "SFNT font table missing";
    00384         case FT_Err_Horiz_Header_Missing :      return "horizontal header (hhea) table missing";
    00385         case FT_Err_Locations_Missing :         return "locations (loca) table missing";
    00386         case FT_Err_Name_Table_Missing :        return "name table missing";
    00387         case FT_Err_CMap_Table_Missing :        return "character map (cmap) table missing";
    00388         case FT_Err_Hmtx_Table_Missing :        return "horizontal metrics (hmtx) table missing";
    00389         case FT_Err_Post_Table_Missing :        return "PostScript (post) table missing";
    00390         case FT_Err_Invalid_Horiz_Metrics :     return "invalid horizontal metrics";
    00391         case FT_Err_Invalid_CharMap_Format :    return "invalid character map (cmap) format";
    00392         case FT_Err_Invalid_PPem :              return "invalid ppem value";
    00393         case FT_Err_Invalid_Vert_Metrics :      return "invalid vertical metrics";
    00394         case FT_Err_Could_Not_Find_Context :    return "could not find context";
    00395         case FT_Err_Invalid_Post_Table_Format : return "invalid PostScript (post) table format";
    00396         case FT_Err_Invalid_Post_Table :        return "invalid PostScript (post) table";
    00397
    00398         // CCF, CID and Type 1 errors
    00399         case FT_Err_Syntax_Error :              return "opcode syntax error";
    00400         case FT_Err_Stack_Underflow :           return "argument stack underflow";
    00401         case FT_Err_Ignore :                    return "ignore";
    00402
    00403         // BDF errors
    00404         case FT_Err_Missing_Startfont_Field :   return "`STARTFONT' field missing";
    00405         case FT_Err_Missing_Font_Field :        return "`FONT' field missing";
    00406         case FT_Err_Missing_Size_Field :        return "`SIZE' field missing";
    00407         case FT_Err_Missing_Chars_Field :       return "`CHARS' field missing";
    00408         case FT_Err_Missing_Startchar_Field :   return "`STARTCHAR' field missing";
    00409         case FT_Err_Missing_Encoding_Field :    return "`ENCODING' field missing";
    00410         case FT_Err_Missing_Bbx_Field :         return "`BBX' field missing";
    00411     }
    00412
    00413     return "unknown error";
    00414 }
    00415
    00416 } // namespace priv
    00417
    00418 } // namespace sf
    00419

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