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 ::