28 #include <SFML/Graphics/FontLoader.hpp>
29 #include <SFML/Graphics/Color.hpp>
30 #include <SFML/Graphics/Font.hpp>
31 #include <SFML/Graphics/Image.hpp>
32 #include <SFML/Graphics/GraphicsContext.hpp>
47 bool operator ()(FT_BitmapGlyph Glyph1, FT_BitmapGlyph Glyph2)
const
49 return Glyph2->bitmap.rows < Glyph1->bitmap.rows;
61 FontLoader& FontLoader::GetInstance()
63 static FontLoader Instance;
72 FontLoader::FontLoader()
75 FT_Error Error = FT_Init_FreeType(&myLibrary);
78 std::cerr <<
"Failed to initialize FreeType library (error code : " << Error <<
")" << std::endl;
87 FontLoader::~FontLoader()
91 FT_Done_FreeType(myLibrary);
98 bool FontLoader::LoadFontFromFile(
const std::string& Filename,
unsigned int CharSize,
const Unicode::UTF32String& Charset, Font& LoadedFont)
103 std::cerr <<
"Failed to load font \"" << Filename <<
"\", FreeType has not been initialized" << std::endl;
109 FT_Error Error = FT_New_Face(myLibrary, Filename.c_str(), 0, &FontFace);
112 std::cerr <<
"Failed to load font \"" << Filename <<
"\" (" << GetErrorDesc(Error) <<
")" << std::endl;
117 Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
119 std::cerr <<
"Failed to load font \"" << Filename <<
"\" (" << GetErrorDesc(Error) <<
")" << std::endl;
122 FT_Done_Face(FontFace);
131 bool FontLoader::LoadFontFromMemory(
const char* Data, std::size_t SizeInBytes,
unsigned int CharSize,
const Unicode::UTF32String& Charset, Font& LoadedFont)
136 std::cerr <<
"Failed to load font from memory, FreeType has not been initialized" << std::endl;
142 FT_Error Error = FT_New_Memory_Face(myLibrary, reinterpret_cast<const FT_Byte*>(Data), static_cast<FT_Long>(SizeInBytes), 0, &FontFace);
145 std::cerr <<
"Failed to load font from memory (" << GetErrorDesc(Error) <<
")" << std::endl;
150 Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
152 std::cerr <<
"Failed to load font from memory (" << GetErrorDesc(Error) <<
")" << std::endl;
155 FT_Done_Face(FontFace);
164 FT_Error FontLoader::CreateBitmapFont(FT_Face FontFace,
unsigned int CharSize,
const Unicode::UTF32String& Charset, Font& LoadedFont)
167 priv::GraphicsContext Ctx;
171 GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxSize));
172 int NbChars =
static_cast<int>(sqrt(static_cast<double>(Charset.length())) * 0.75);
175 if (NbChars * CharSize >= static_cast<unsigned int>(MaxSize))
176 CharSize = MaxSize / NbChars;
179 unsigned int Left = 0;
180 unsigned int Top = 0;
182 unsigned int TexHeight = CharSize * NbChars;
183 std::vector<unsigned int> Tops(TexWidth, 0);
186 std::vector<Uint8> GlyphsBuffer(TexWidth * TexHeight * 4);
189 FT_Error Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
194 Error = FT_Select_Charmap(FontFace, FT_ENCODING_UNICODE);
199 typedef std::multimap<FT_BitmapGlyph, Uint32, SizeCompare> GlyphTable;
201 for (std::size_t i = 0; i < Charset.length(); ++i)
204 Error = FT_Load_Char(FontFace, Charset[i], FT_LOAD_TARGET_NORMAL);
210 Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
213 FT_Glyph_To_Bitmap(&Glyph, FT_RENDER_MODE_NORMAL, 0, 1);
214 FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
217 Glyphs.insert(std::make_pair(BitmapGlyph, Charset[i]));
221 unsigned int MaxHeight = 0;
222 std::map<Uint32, IntRect> Coords;
223 for (GlyphTable::const_iterator i = Glyphs.begin(); i != Glyphs.end(); ++i)
226 Glyph& CurGlyph = LoadedFont.myGlyphs[i->second];
227 FT_BitmapGlyph BitmapGlyph = i->first;
228 FT_Bitmap& Bitmap = BitmapGlyph->bitmap;
231 if (Left + Bitmap.width + 1 >= TexWidth)
236 for (
int x = 0; x < Bitmap.width + 1; ++x)
237 Top = std::max(Top, Tops[Left + x]);
241 if (Top + Bitmap.rows + 1 >= TexHeight)
244 GlyphsBuffer.resize(TexWidth * TexHeight * 4);
248 CurGlyph.Rectangle.Left = BitmapGlyph->left;
249 CurGlyph.Rectangle.Top = -BitmapGlyph->top;
250 CurGlyph.Rectangle.Right = CurGlyph.Rectangle.Left + Bitmap.width;
251 CurGlyph.Rectangle.Bottom = Bitmap.rows - BitmapGlyph->top;
252 CurGlyph.Advance = BitmapGlyph->root.advance.x >> 16;
255 Coords[i->second] = IntRect(Left + 1, Top + 1, Left + Bitmap.width + 1, Top + Bitmap.rows + 1);
258 const Uint8* Pixels = Bitmap.buffer;
259 for (
int y = 0; y < Bitmap.rows; ++y)
261 for (
int x = 0; x < Bitmap.width; ++x)
263 std::size_t Index = x + Left + 1 + (y + Top + 1) * TexWidth;
264 GlyphsBuffer[Index * 4 + 0] = 255;
265 GlyphsBuffer[Index * 4 + 1] = 255;
266 GlyphsBuffer[Index * 4 + 2] = 255;
267 GlyphsBuffer[Index * 4 + 3] = Pixels[x];
269 Pixels += Bitmap.pitch;
273 for (
int x = 0; x < Bitmap.width + 1; ++x)
274 Tops[Left + x] = Top + Bitmap.rows;
275 Left += Bitmap.width + 1;
276 if (Top + Bitmap.rows > MaxHeight)
277 MaxHeight = Top + Bitmap.rows;
280 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
284 TexHeight = MaxHeight + 1;
285 GlyphsBuffer.resize(TexWidth * TexHeight * 4);
286 LoadedFont.myTexture.LoadFromPixels(TexWidth, TexHeight, &GlyphsBuffer[0]);
289 for (std::size_t i = 0; i < Charset.size(); ++i)
291 Uint32 CurChar = Charset[i];
292 LoadedFont.myGlyphs[CurChar].TexCoords = LoadedFont.myTexture.GetTexCoords(Coords[CurChar]);
296 LoadedFont.myCharSize = CharSize;
305 std::string FontLoader::GetErrorDesc(FT_Error Error)
310 case FT_Err_Cannot_Open_Resource :
return "cannot open resource";
311 case FT_Err_Unknown_File_Format :
return "unknown file format";
312 case FT_Err_Invalid_File_Format :
return "broken file";
313 case FT_Err_Invalid_Version :
return "invalid FreeType version";
314 case FT_Err_Lower_Module_Version :
return "module version is too low";
315 case FT_Err_Invalid_Argument :
return "invalid argument";
316 case FT_Err_Unimplemented_Feature :
return "unimplemented feature";
317 case FT_Err_Invalid_Table :
return "broken table";
318 case FT_Err_Invalid_Offset :
return "broken offset within table";
321 case FT_Err_Invalid_Glyph_Index :
return "invalid glyph index";
322 case FT_Err_Invalid_Character_Code :
return "invalid character code";
323 case FT_Err_Invalid_Glyph_Format :
return "unsupported glyph image format";
324 case FT_Err_Cannot_Render_Glyph :
return "cannot render this glyph format";
325 case FT_Err_Invalid_Outline :
return "invalid outline";
326 case FT_Err_Invalid_Composite :
return "invalid composite glyph";
327 case FT_Err_Too_Many_Hints :
return "too many hints";
328 case FT_Err_Invalid_Pixel_Size :
return "invalid pixel size";
331 case FT_Err_Invalid_Handle :
return "invalid object handle";
332 case FT_Err_Invalid_Library_Handle :
return "invalid library handle";
333 case FT_Err_Invalid_Driver_Handle :
return "invalid module handle";
334 case FT_Err_Invalid_Face_Handle :
return "invalid face handle";
335 case FT_Err_Invalid_Size_Handle :
return "invalid size handle";
336 case FT_Err_Invalid_Slot_Handle :
return "invalid glyph slot handle";
337 case FT_Err_Invalid_CharMap_Handle :
return "invalid charmap handle";
338 case FT_Err_Invalid_Cache_Handle :
return "invalid cache manager handle";
339 case FT_Err_Invalid_Stream_Handle :
return "invalid stream handle";
342 case FT_Err_Too_Many_Drivers :
return "too many modules";
343 case FT_Err_Too_Many_Extensions :
return "too many extensions";
346 case FT_Err_Out_Of_Memory :
return "out of memory";
347 case FT_Err_Unlisted_Object :
return "unlisted object";
350 case FT_Err_Cannot_Open_Stream :
return "cannot open stream";
351 case FT_Err_Invalid_Stream_Seek :
return "invalid stream seek";
352 case FT_Err_Invalid_Stream_Skip :
return "invalid stream skip";
353 case FT_Err_Invalid_Stream_Read :
return "invalid stream read";
354 case FT_Err_Invalid_Stream_Operation :
return "invalid stream operation";
355 case FT_Err_Invalid_Frame_Operation :
return "invalid frame operation";
356 case FT_Err_Nested_Frame_Access :
return "nested frame access";
357 case FT_Err_Invalid_Frame_Read :
return "invalid frame read";
360 case FT_Err_Raster_Uninitialized :
return "raster uninitialized";
361 case FT_Err_Raster_Corrupted :
return "raster corrupted";
362 case FT_Err_Raster_Overflow :
return "raster overflow";
363 case FT_Err_Raster_Negative_Height :
return "negative height while rastering";
366 case FT_Err_Too_Many_Caches :
return "too many registered caches";
369 case FT_Err_Invalid_Opcode :
return "invalid opcode";
370 case FT_Err_Too_Few_Arguments :
return "too few arguments";
371 case FT_Err_Stack_Overflow :
return "stack overflow";
372 case FT_Err_Code_Overflow :
return "code overflow";
373 case FT_Err_Bad_Argument :
return "bad argument";
374 case FT_Err_Divide_By_Zero :
return "division by zero";
375 case FT_Err_Invalid_Reference :
return "invalid reference";
376 case FT_Err_Debug_OpCode :
return "found debug opcode";
377 case FT_Err_ENDF_In_Exec_Stream :
return "found ENDF opcode in execution stream";
378 case FT_Err_Nested_DEFS :
return "nested DEFS";
379 case FT_Err_Invalid_CodeRange :
return "invalid code range";
380 case FT_Err_Execution_Too_Long :
return "execution context too long";
381 case FT_Err_Too_Many_Function_Defs :
return "too many function definitions";
382 case FT_Err_Too_Many_Instruction_Defs :
return "too many instruction definitions";
383 case FT_Err_Table_Missing :
return "SFNT font table missing";
384 case FT_Err_Horiz_Header_Missing :
return "horizontal header (hhea) table missing";
385 case FT_Err_Locations_Missing :
return "locations (loca) table missing";
386 case FT_Err_Name_Table_Missing :
return "name table missing";
387 case FT_Err_CMap_Table_Missing :
return "character map (cmap) table missing";
388 case FT_Err_Hmtx_Table_Missing :
return "horizontal metrics (hmtx) table missing";
389 case FT_Err_Post_Table_Missing :
return "PostScript (post) table missing";
390 case FT_Err_Invalid_Horiz_Metrics :
return "invalid horizontal metrics";
391 case FT_Err_Invalid_CharMap_Format :
return "invalid character map (cmap) format";
392 case FT_Err_Invalid_PPem :
return "invalid ppem value";
393 case FT_Err_Invalid_Vert_Metrics :
return "invalid vertical metrics";
394 case FT_Err_Could_Not_Find_Context :
return "could not find context";
395 case FT_Err_Invalid_Post_Table_Format :
return "invalid PostScript (post) table format";
396 case FT_Err_Invalid_Post_Table :
return "invalid PostScript (post) table";
399 case FT_Err_Syntax_Error :
return "opcode syntax error";
400 case FT_Err_Stack_Underflow :
return "argument stack underflow";
401 case FT_Err_Ignore :
return "ignore";
404 case FT_Err_Missing_Startfont_Field :
return "`STARTFONT' field missing";
405 case FT_Err_Missing_Font_Field :
return "`FONT' field missing";
406 case FT_Err_Missing_Size_Field :
return "`SIZE' field missing";
407 case FT_Err_Missing_Chars_Field :
return "`CHARS' field missing";
408 case FT_Err_Missing_Startchar_Field :
return "`STARTCHAR' field missing";
409 case FT_Err_Missing_Encoding_Field :
return "`ENCODING' field missing";
410 case FT_Err_Missing_Bbx_Field :
return "`BBX' field missing";
413 return "unknown error";
static unsigned int GetValidTextureSize(unsigned int Size)
Get a valid texture size according to hardware support.