FontLoader.cpp
00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Laurent Gomila ([email protected]) 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 ::