summaryrefslogtreecommitdiff
path: root/src/SFML/Graphics/FontLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/SFML/Graphics/FontLoader.cpp')
-rwxr-xr-xsrc/SFML/Graphics/FontLoader.cpp419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/SFML/Graphics/FontLoader.cpp b/src/SFML/Graphics/FontLoader.cpp
new file mode 100755
index 0000000..209454e
--- /dev/null
+++ b/src/SFML/Graphics/FontLoader.cpp
@@ -0,0 +1,419 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Graphics/FontLoader.hpp>
+#include <SFML/Graphics/Color.hpp>
+#include <SFML/Graphics/Font.hpp>
+#include <SFML/Graphics/Image.hpp>
+#include <SFML/Graphics/Renderer.hpp>
+#include <iostream>
+#include <vector>
+#include <math.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+// Static member data
+////////////////////////////////////////////////////////////
+wchar_t FontLoader::ourDefaultCharset[] =
+{
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
+ 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
+ 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
+ 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
+ 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
+ 252, 253, 254, 255, 0
+};
+
+
+////////////////////////////////////////////////////////////
+/// Get the unique instance of the class
+////////////////////////////////////////////////////////////
+FontLoader& FontLoader::GetInstance()
+{
+ static FontLoader Instance;
+
+ return Instance;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+FontLoader::FontLoader()
+{
+ // Initialize FreeType library
+ FT_Error Error = FT_Init_FreeType(&myLibrary);
+ if (Error)
+ {
+ std::cerr << "Failed to initialize FreeType library (error code : " << Error << ")" << std::endl;
+ return;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Destructor
+////////////////////////////////////////////////////////////
+FontLoader::~FontLoader()
+{
+ // Shutdown FreeType library
+ if (myLibrary)
+ FT_Done_FreeType(myLibrary);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Load a font from a file
+////////////////////////////////////////////////////////////
+bool FontLoader::LoadFontFromFile(const std::string& Filename, unsigned int CharSize, std::wstring Charset, Font& LoadedFont)
+{
+ // Check if Freetype is correctly initialized
+ if (!myLibrary)
+ {
+ std::cerr << "Failed to load font \"" << Filename << "\", FreeType has not been initialized" << std::endl;
+ return false;
+ }
+
+ // Create a new font face from the specified file
+ FT_Face FontFace;
+ FT_Error Error = FT_New_Face(myLibrary, Filename.c_str(), 0, &FontFace);
+ if (Error)
+ {
+ std::cerr << "Failed to load font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
+ return false;
+ }
+
+ // Create the bitmap font
+ Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
+ if (Error)
+ std::cerr << "Failed to load font \"" << Filename << "\" (" << GetErrorDesc(Error) << ")" << std::endl;
+
+ // Delete the font
+ FT_Done_Face(FontFace);
+
+ return Error == 0;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Load the font from a file in memory
+////////////////////////////////////////////////////////////
+bool FontLoader::LoadFontFromMemory(const char* Data, std::size_t SizeInBytes, unsigned int CharSize, std::wstring Charset, Font& LoadedFont)
+{
+ // Check if Freetype is correctly initialized
+ if (!myLibrary)
+ {
+ std::cerr << "Failed to load font from memory, FreeType has not been initialized" << std::endl;
+ return false;
+ }
+
+ // Create a new font face from the specified memory data
+ FT_Face FontFace;
+ FT_Error Error = FT_New_Memory_Face(myLibrary, reinterpret_cast<const FT_Byte*>(Data), static_cast<FT_Long>(SizeInBytes), 0, &FontFace);
+ if (Error)
+ {
+ std::cerr << "Failed to load font from memory (" << GetErrorDesc(Error) << ")" << std::endl;
+ return false;
+ }
+
+ // Create the bitmap font
+ Error = CreateBitmapFont(FontFace, CharSize, Charset, LoadedFont);
+ if (Error)
+ std::cerr << "Failed to load font from memory (" << GetErrorDesc(Error) << ")" << std::endl;
+
+ // Delete the font
+ FT_Done_Face(FontFace);
+
+ return Error == 0;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Create a bitmap font from a font face and a characters set
+////////////////////////////////////////////////////////////
+FT_Error FontLoader::CreateBitmapFont(FT_Face FontFace, unsigned int CharSize, std::wstring Charset, Font& LoadedFont)
+{
+ // If no characters set has been provided, we take the default one (31 - 255 ASCII codes)
+ if (Charset.empty())
+ Charset = ourDefaultCharset;
+
+ // Always add these special characters
+ Charset += L" \n\v\t";
+
+ // Clear the font's previous character map
+ LoadedFont.myCharacters.clear();
+
+ // Let's find how many characters to put in each row to make them fit into a squared texture
+ GLint MaxSize;
+ GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxSize));
+ int NbChars = static_cast<int>(sqrt(static_cast<double>(Charset.length())) * 0.75);
+
+ // Clamp the character size to make sure we won't create a texture too big
+ if (NbChars * CharSize >= static_cast<unsigned int>(MaxSize))
+ CharSize = MaxSize / NbChars;
+
+ // Initialize the dimensions
+ unsigned int Left = 0;
+ unsigned int Top = 0;
+ unsigned int TexWidth = Image::GetValidTextureSize(CharSize * NbChars);
+ unsigned int TexHeight = Image::GetValidTextureSize(CharSize * NbChars);
+ std::vector<unsigned int> Tops(TexWidth, 0);
+
+ // Create the bitmap font (all black for now -- we're going to fill it up)
+ LoadedFont.myTexture.Create(TexWidth, TexHeight, Color(0, 0, 0, 0));
+
+ // Setup the font size
+ FT_Error Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
+ if (Error)
+ return Error;
+
+ // Select the unicode character map
+ Error = FT_Select_Charmap(FontFace, FT_ENCODING_UNICODE);
+ if (Error)
+ return Error;
+
+ // Render the characters set to a bitmap
+ std::map<wchar_t, IntRect> Coords;
+ for (std::size_t i = 0; i < Charset.length(); ++i)
+ {
+ // Get the current character to generate
+ wchar_t c = Charset[i];
+ Font::Character& CurChar = LoadedFont.myCharacters[c];
+
+ // Load the glyph corresponding to the current character
+ Error = FT_Load_Char(FontFace, c, FT_LOAD_DEFAULT);
+ if (Error)
+ return Error;
+
+ // Convert the glyph to a bitmap (ie. rasterize it)
+ FT_Glyph Glyph;
+ Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
+ if (Error)
+ return Error;
+ FT_Glyph_To_Bitmap(&Glyph, ft_render_mode_normal, 0, 1);
+ FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
+ FT_Bitmap& Bitmap = BitmapGlyph->bitmap;
+
+ // Should we handle other pixel modes ?
+ if (Bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
+ return FT_Err_Cannot_Render_Glyph;
+
+ // Make sure we don't go over the texture width
+ if (Left + Bitmap.width + 1 >= TexWidth)
+ Left = 0;
+
+ // Compute the top coordinate
+ Top = Tops[Left];
+ for (int x = 0; x < Bitmap.width + 1; ++x)
+ Top = std::max(Top, Tops[Left + x]);
+ Top++;
+
+ // Make sure we don't go over the texture height -- resize it if we need more space
+ if (Top + Bitmap.rows + 1 >= TexHeight)
+ {
+ TexHeight *= 2;
+ LoadedFont.myTexture.Resize(TexWidth, TexHeight, Color(0, 0, 0, 0));
+ }
+
+ // Store the character's position and size
+ CurChar.Rect.Left = BitmapGlyph->left;
+ CurChar.Rect.Top = -BitmapGlyph->top;
+ CurChar.Rect.Right = CurChar.Rect.Left + Bitmap.width;
+ CurChar.Rect.Bottom = Bitmap.rows - BitmapGlyph->top;
+ CurChar.Advance = FontFace->glyph->advance.x / 64;
+
+ // Texture size may change, so let the texture coordinates be calculated later
+ Coords[c] = IntRect(Left + 1, Top + 1, Left + Bitmap.width + 1, Top + Bitmap.rows + 1);
+
+ // Draw the glyph into our bitmap font
+ const Uint8* Pixels = Bitmap.buffer;
+ for (int y = 0; y < Bitmap.rows; ++y)
+ {
+ for (int x = 0; x < Bitmap.width; ++x)
+ {
+ LoadedFont.myTexture.SetPixel(x + Left + 1, y + Top + 1, Color(255, 255, 255, Pixels[x]));
+ }
+ Pixels += Bitmap.pitch;
+ }
+
+ // Update the rendering coordinates
+ for (int x = 0; x < Bitmap.width + 1; ++x)
+ Tops[Left + x] = Top + Bitmap.rows;
+ Left += Bitmap.width + 1;
+
+ // Delete the glyph
+ FT_Done_Glyph(Glyph);
+ }
+
+ // Now that the texture has its final size, we can precompute texture coordinates
+ for (std::size_t i = 0; i < Charset.size(); ++i)
+ {
+ wchar_t c = Charset[i];
+ LoadedFont.myCharacters[c].Coord = LoadedFont.myTexture.GetTexCoords(Coords[c], false);
+ }
+
+ // Update the character size (it may have been changed by the function)
+ LoadedFont.myCharSize = CharSize;
+
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get a description from a FT error code
+////////////////////////////////////////////////////////////
+std::string FontLoader::GetErrorDesc(FT_Error Error)
+{
+ switch (Error)
+ {
+ // Generic errors
+ case FT_Err_Cannot_Open_Resource : return "cannot open resource";
+ case FT_Err_Unknown_File_Format : return "unknown file format";
+ case FT_Err_Invalid_File_Format : return "broken file";
+ case FT_Err_Invalid_Version : return "invalid FreeType version";
+ case FT_Err_Lower_Module_Version : return "module version is too low";
+ case FT_Err_Invalid_Argument : return "invalid argument";
+ case FT_Err_Unimplemented_Feature : return "unimplemented feature";
+ case FT_Err_Invalid_Table : return "broken table";
+ case FT_Err_Invalid_Offset : return "broken offset within table";
+
+ // Glyph / character errors
+ case FT_Err_Invalid_Glyph_Index : return "invalid glyph index";
+ case FT_Err_Invalid_Character_Code : return "invalid character code";
+ case FT_Err_Invalid_Glyph_Format : return "unsupported glyph image format";
+ case FT_Err_Cannot_Render_Glyph : return "cannot render this glyph format";
+ case FT_Err_Invalid_Outline : return "invalid outline";
+ case FT_Err_Invalid_Composite : return "invalid composite glyph";
+ case FT_Err_Too_Many_Hints : return "too many hints";
+ case FT_Err_Invalid_Pixel_Size : return "invalid pixel size";
+
+ // Handle errors
+ case FT_Err_Invalid_Handle : return "invalid object handle";
+ case FT_Err_Invalid_Library_Handle : return "invalid library handle";
+ case FT_Err_Invalid_Driver_Handle : return "invalid module handle";
+ case FT_Err_Invalid_Face_Handle : return "invalid face handle";
+ case FT_Err_Invalid_Size_Handle : return "invalid size handle";
+ case FT_Err_Invalid_Slot_Handle : return "invalid glyph slot handle";
+ case FT_Err_Invalid_CharMap_Handle : return "invalid charmap handle";
+ case FT_Err_Invalid_Cache_Handle : return "invalid cache manager handle";
+ case FT_Err_Invalid_Stream_Handle : return "invalid stream handle";
+
+ // Driver errors
+ case FT_Err_Too_Many_Drivers : return "too many modules";
+ case FT_Err_Too_Many_Extensions : return "too many extensions";
+
+ // Memory errors
+ case FT_Err_Out_Of_Memory : return "out of memory";
+ case FT_Err_Unlisted_Object : return "unlisted object";
+
+ // Stream errors
+ case FT_Err_Cannot_Open_Stream : return "cannot open stream";
+ case FT_Err_Invalid_Stream_Seek : return "invalid stream seek";
+ case FT_Err_Invalid_Stream_Skip : return "invalid stream skip";
+ case FT_Err_Invalid_Stream_Read : return "invalid stream read";
+ case FT_Err_Invalid_Stream_Operation : return "invalid stream operation";
+ case FT_Err_Invalid_Frame_Operation : return "invalid frame operation";
+ case FT_Err_Nested_Frame_Access : return "nested frame access";
+ case FT_Err_Invalid_Frame_Read : return "invalid frame read";
+
+ // Raster errors
+ case FT_Err_Raster_Uninitialized : return "raster uninitialized";
+ case FT_Err_Raster_Corrupted : return "raster corrupted";
+ case FT_Err_Raster_Overflow : return "raster overflow";
+ case FT_Err_Raster_Negative_Height : return "negative height while rastering";
+
+ // Cache errors
+ case FT_Err_Too_Many_Caches : return "too many registered caches";
+
+ // TrueType and SFNT errors
+ case FT_Err_Invalid_Opcode : return "invalid opcode";
+ case FT_Err_Too_Few_Arguments : return "too few arguments";
+ case FT_Err_Stack_Overflow : return "stack overflow";
+ case FT_Err_Code_Overflow : return "code overflow";
+ case FT_Err_Bad_Argument : return "bad argument";
+ case FT_Err_Divide_By_Zero : return "division by zero";
+ case FT_Err_Invalid_Reference : return "invalid reference";
+ case FT_Err_Debug_OpCode : return "found debug opcode";
+ case FT_Err_ENDF_In_Exec_Stream : return "found ENDF opcode in execution stream";
+ case FT_Err_Nested_DEFS : return "nested DEFS";
+ case FT_Err_Invalid_CodeRange : return "invalid code range";
+ case FT_Err_Execution_Too_Long : return "execution context too long";
+ case FT_Err_Too_Many_Function_Defs : return "too many function definitions";
+ case FT_Err_Too_Many_Instruction_Defs : return "too many instruction definitions";
+ case FT_Err_Table_Missing : return "SFNT font table missing";
+ case FT_Err_Horiz_Header_Missing : return "horizontal header (hhea) table missing";
+ case FT_Err_Locations_Missing : return "locations (loca) table missing";
+ case FT_Err_Name_Table_Missing : return "name table missing";
+ case FT_Err_CMap_Table_Missing : return "character map (cmap) table missing";
+ case FT_Err_Hmtx_Table_Missing : return "horizontal metrics (hmtx) table missing";
+ case FT_Err_Post_Table_Missing : return "PostScript (post) table missing";
+ case FT_Err_Invalid_Horiz_Metrics : return "invalid horizontal metrics";
+ case FT_Err_Invalid_CharMap_Format : return "invalid character map (cmap) format";
+ case FT_Err_Invalid_PPem : return "invalid ppem value";
+ case FT_Err_Invalid_Vert_Metrics : return "invalid vertical metrics";
+ case FT_Err_Could_Not_Find_Context : return "could not find context";
+ case FT_Err_Invalid_Post_Table_Format : return "invalid PostScript (post) table format";
+ case FT_Err_Invalid_Post_Table : return "invalid PostScript (post) table";
+
+ // CCF, CID and Type 1 errors
+ case FT_Err_Syntax_Error : return "opcode syntax error";
+ case FT_Err_Stack_Underflow : return "argument stack underflow";
+ case FT_Err_Ignore : return "ignore";
+
+ // BDF errors
+ case FT_Err_Missing_Startfont_Field : return "`STARTFONT' field missing";
+ case FT_Err_Missing_Font_Field : return "`FONT' field missing";
+ case FT_Err_Missing_Size_Field : return "`SIZE' field missing";
+ case FT_Err_Missing_Chars_Field : return "`CHARS' field missing";
+ case FT_Err_Missing_Startchar_Field : return "`STARTCHAR' field missing";
+ case FT_Err_Missing_Encoding_Field : return "`ENCODING' field missing";
+ case FT_Err_Missing_Bbx_Field : return "`BBX' field missing";
+ }
+
+ return "unknown error";
+}
+
+} // namespace priv
+
+} // namespace sf
+