FontLoader.cpp
1 //
3 // SFML - Simple and Fast Multimedia Library
4 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
5 //
6 // This software is provided 'as-is', without any express or implied warranty.
7 // In no event will the authors be held liable for any damages arising from the use of this software.
8 //
9 // Permission is granted to anyone to use this software for any purpose,
10 // including commercial applications, and to alter it and redistribute it freely,
11 // subject to the following restrictions:
12 //
13 // 1. The origin of this software must not be misrepresented;
14 // you must not claim that you wrote the original software.
15 // If you use this software in a product, an acknowledgment
16 // in the product documentation would be appreciated but is not required.
17 //
18 // 2. Altered source versions must be plainly marked as such,
19 // and must not be misrepresented as being the original software.
20 //
21 // 3. This notice may not be removed or altered from any source distribution.
22 //
24 
26 // Headers
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>
33 #include FT_GLYPH_H
34 #include <iostream>
35 #include <map>
36 #include <vector>
37 #include <math.h>
38 
39 
40 namespace
41 {
43  // Functor to sort glyphs by size
45  struct SizeCompare
46  {
47  bool operator ()(FT_BitmapGlyph Glyph1, FT_BitmapGlyph Glyph2) const
48  {
49  return Glyph2->bitmap.rows < Glyph1->bitmap.rows;
50  }
51  };
52 }
53 
54 namespace sf
55 {
56 namespace priv
57 {
61 FontLoader& FontLoader::GetInstance()
62 {
63  static FontLoader Instance;
64 
65  return Instance;
66 }
67 
68 
72 FontLoader::FontLoader()
73 {
74  // Initialize FreeType library
75  FT_Error Error = FT_Init_FreeType(&myLibrary);
76  if (Error)
77  {
78  std::cerr << "Failed to initialize FreeType library (error code : " << Error << ")" << std::endl;
79  return;
80  }
81 }
82 
83 
87 FontLoader::~FontLoader()
88 {
89  // Shutdown FreeType library
90  if (myLibrary)
91  FT_Done_FreeType(myLibrary);
92 }
93 
94 
98 bool FontLoader::LoadFontFromFile(const std::string& Filename, unsigned int CharSize, const Unicode::UTF32String& Charset, Font& LoadedFont)
99 {
100  // Check if Freetype is correctly initialized
101  if (!myLibrary)
102  {
103  std::cerr << "Failed to load font \"" << Filename << "\", FreeType has not been initialized" << std::endl;
104  return false;
105  }
106 
107  // Create a new font face from the specified file
108  FT_Face FontFace;
109  FT_Error Error = FT_New_Face(myLibrary, Filename.c_str(), 0, &FontFace);
110  if (Error)
111  {
112  std::cerr << "Failed to load font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
113  return false;
114  }
115 
116  // Create the bitmap font
117  Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
118  if (Error)
119  std::cerr << "Failed to load font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
120 
121  // Delete the font
122  FT_Done_Face(FontFace);
123 
124  return Error == 0;
125 }
126 
127 
131 bool FontLoader::LoadFontFromMemory(const char* Data, std::size_t SizeInBytes, unsigned int CharSize, const Unicode::UTF32String& Charset, Font& LoadedFont)
132 {
133  // Check if Freetype is correctly initialized
134  if (!myLibrary)
135  {
136  std::cerr << "Failed to load font from memory, FreeType has not been initialized" << std::endl;
137  return false;
138  }
139 
140  // Create a new font face from the specified memory data
141  FT_Face FontFace;
142  FT_Error Error = FT_New_Memory_Face(myLibrary, reinterpret_cast<const FT_Byte*>(Data), static_cast<FT_Long>(SizeInBytes), 0, &FontFace);
143  if (Error)
144  {
145  std::cerr << "Failed to load font from memory (" << GetErrorDesc(Error) << ")" << std::endl;
146  return false;
147  }
148 
149  // Create the bitmap font
150  Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
151  if (Error)
152  std::cerr << "Failed to load font from memory (" << GetErrorDesc(Error) << ")" << std::endl;
153 
154  // Delete the font
155  FT_Done_Face(FontFace);
156 
157  return Error == 0;
158 }
159 
160 
164 FT_Error FontLoader::CreateBitmapFont(FT_Face FontFace, unsigned int CharSize, const Unicode::UTF32String& Charset, Font& LoadedFont)
165 {
166  // Make sure we have a valid context
167  priv::GraphicsContext Ctx;
168 
169  // Let's find how many characters to put in each row to make them fit into a squared texture
170  GLint MaxSize;
171  GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxSize));
172  int NbChars = static_cast<int>(sqrt(static_cast<double>(Charset.length())) * 0.75);
173 
174  // Clamp the character size to make sure we won't create a texture too big
175  if (NbChars * CharSize >= static_cast<unsigned int>(MaxSize))
176  CharSize = MaxSize / NbChars;
177 
178  // Initialize the dimensions
179  unsigned int Left = 0;
180  unsigned int Top = 0;
181  unsigned int TexWidth = Image::GetValidTextureSize(CharSize * NbChars);
182  unsigned int TexHeight = CharSize * NbChars;
183  std::vector<unsigned int> Tops(TexWidth, 0);
184 
185  // Create a pixel buffer for rendering every glyph
186  std::vector<Uint8> GlyphsBuffer(TexWidth * TexHeight * 4);
187 
188  // Setup the font size
189  FT_Error Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
190  if (Error)
191  return Error;
192 
193  // Select the unicode character map
194  Error = FT_Select_Charmap(FontFace, FT_ENCODING_UNICODE);
195  if (Error)
196  return Error;
197 
198  // Render all glyphs and sort them by size to optimize texture space
199  typedef std::multimap<FT_BitmapGlyph, Uint32, SizeCompare> GlyphTable;
200  GlyphTable Glyphs;
201  for (std::size_t i = 0; i < Charset.length(); ++i)
202  {
203  // Load the glyph corresponding to the current character
204  Error = FT_Load_Char(FontFace, Charset[i], FT_LOAD_TARGET_NORMAL);
205  if (Error)
206  return Error;
207 
208  // Convert the glyph to a bitmap (ie. rasterize it)
209  FT_Glyph Glyph;
210  Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
211  if (Error)
212  return Error;
213  FT_Glyph_To_Bitmap(&Glyph, FT_RENDER_MODE_NORMAL, 0, 1);
214  FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
215 
216  // Add it to the sorted table of glyphs
217  Glyphs.insert(std::make_pair(BitmapGlyph, Charset[i]));
218  }
219 
220  // Copy the rendered glyphs into the texture
221  unsigned int MaxHeight = 0;
222  std::map<Uint32, IntRect> Coords;
223  for (GlyphTable::const_iterator i = Glyphs.begin(); i != Glyphs.end(); ++i)
224  {
225  // Get the bitmap of the current glyph
226  Glyph& CurGlyph = LoadedFont.myGlyphs[i->second];
227  FT_BitmapGlyph BitmapGlyph = i->first;
228  FT_Bitmap& Bitmap = BitmapGlyph->bitmap;
229 
230  // Make sure we don't go over the texture width
231  if (Left + Bitmap.width + 1 >= TexWidth)
232  Left = 0;
233 
234  // Compute the top coordinate
235  Top = Tops[Left];
236  for (int x = 0; x < Bitmap.width + 1; ++x)
237  Top = std::max(Top, Tops[Left + x]);
238  Top++;
239 
240  // Make sure we don't go over the texture height -- resize it if we need more space
241  if (Top + Bitmap.rows + 1 >= TexHeight)
242  {
243  TexHeight *= 2;
244  GlyphsBuffer.resize(TexWidth * TexHeight * 4);
245  }
246 
247  // Store the character's position and size
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;
253 
254  // Texture size may change, so let the texture coordinates be calculated later
255  Coords[i->second] = IntRect(Left + 1, Top + 1, Left + Bitmap.width + 1, Top + Bitmap.rows + 1);
256 
257  // Draw the glyph into our bitmap font
258  const Uint8* Pixels = Bitmap.buffer;
259  for (int y = 0; y < Bitmap.rows; ++y)
260  {
261  for (int x = 0; x < Bitmap.width; ++x)
262  {
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];
268  }
269  Pixels += Bitmap.pitch;
270  }
271 
272  // Update the rendering coordinates
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;
278 
279  // Delete the glyph
280  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
281  }
282 
283  // Create the font's texture
284  TexHeight = MaxHeight + 1;
285  GlyphsBuffer.resize(TexWidth * TexHeight * 4);
286  LoadedFont.myTexture.LoadFromPixels(TexWidth, TexHeight, &GlyphsBuffer[0]);
287 
288  // Now that the texture is created, we can precompute texture coordinates
289  for (std::size_t i = 0; i < Charset.size(); ++i)
290  {
291  Uint32 CurChar = Charset[i];
292  LoadedFont.myGlyphs[CurChar].TexCoords = LoadedFont.myTexture.GetTexCoords(Coords[CurChar]);
293  }
294 
295  // Update the character size (it may have been changed by the function)
296  LoadedFont.myCharSize = CharSize;
297 
298  return 0;
299 }
300 
301 
305 std::string FontLoader::GetErrorDesc(FT_Error Error)
306 {
307  switch (Error)
308  {
309  // Generic errors
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";
319 
320  // Glyph / character errors
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";
329 
330  // Handle errors
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";
340 
341  // Driver errors
342  case FT_Err_Too_Many_Drivers : return "too many modules";
343  case FT_Err_Too_Many_Extensions : return "too many extensions";
344 
345  // Memory errors
346  case FT_Err_Out_Of_Memory : return "out of memory";
347  case FT_Err_Unlisted_Object : return "unlisted object";
348 
349  // Stream errors
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";
358 
359  // Raster errors
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";
364 
365  // Cache errors
366  case FT_Err_Too_Many_Caches : return "too many registered caches";
367 
368  // TrueType and SFNT errors
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";
397 
398  // CCF, CID and Type 1 errors
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";
402 
403  // BDF errors
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";
411  }
412 
413  return "unknown error";
414 }
415 
416 } // namespace priv
417 
418 } // namespace sf
419 
static unsigned int GetValidTextureSize(unsigned int Size)
Get a valid texture size according to hardware support.
Definition: Image.cpp:560
Left arrow.
Definition: Event.hpp:114