// Get the kerning between two characters float Font::GetKerning( char first, char second, unsigned int size ) { // If anything is invalid, there's no kerning if ( first == 0 || second == 0 || size == 0 || !_fontFace ) { return 0.0f; } if ( FT_HAS_KERNING( _myFontFace ) && SetCurrentSize( size ) ) { // Get the characters as indices FT_UInt firstIndex = FT_Get_Char_Index( _myFontFace, first ); FT_UInt secondIndex = FT_Get_Char_Index( _myFontFace, second ); // Get the kerning vector FT_Vector kerning; FT_Get_Kerning( _myFontFace, firstIndex, secondIndex, FT_KERNING_DEFAULT, &kerning ); // We don't need to apply the kerning scale to bitmap fonts float scale = ( FT_IS_SCALABLE( _myFontFace ) ? KerningScale : 1.0f ); return kerning.x * scale; } return 0.0f; }
// Get the spacing between two lines float Font::GetLineSpacing( unsigned int size ) { if ( _fontFace && SetCurrentSize( size ) ) { return _myFontFace->size->metrics.height * KerningScale; } return 0.0f; }
// Attempts to load font information from a file bool Font::LoadFromFile( const std::string& fname ) { // Remove any loaded information Dispose(); // Attempt to create our FreeType library FT_Library library; if ( 0 != FT_Init_FreeType( &library ) ) { #if defined( _DEBUG ) || defined( DEBUG ) std::cout << "Failed to initialize FreeType for '" << fname << "'." << std::endl; #endif return false; } _library = library; // Attempt to load the font face FT_Face fontFace; if ( 0 != FT_New_Face( library, fname.c_str(), 0, &fontFace ) ) { #if defined( _DEBUG ) || defined( DEBUG ) std::cout << "Failed to create font face for '" << fname << "'." << std::endl; #endif return false; } _fontFace = fontFace; // Get the font name _fontName = fontFace->family_name ? fontFace->family_name : "N/A"; // Attempt to select the Unicode character map if ( 0 != FT_Select_Charmap( fontFace, FT_ENCODING_UNICODE ) ) { #if defined( _DEBUG ) || defined( DEBUG ) std::cout << "Failed to select unicode font for '" << fname << "'." << std::endl; #endif Dispose(); return false; } // Set our default font size to be 12 SetCurrentSize( 12U ); return true; }
int Font::GetKerning(Uint32 first, Uint32 second, unsigned int characterSize) const { // Special case where first or second is 0 (null character) if (first == 0 || second == 0) return 0; FT_Face face = static_cast<FT_Face>(myFace); if (face && FT_HAS_KERNING(face) && SetCurrentSize(characterSize)) { // Convert the characters to indices FT_UInt index1 = FT_Get_Char_Index(face, first); FT_UInt index2 = FT_Get_Char_Index(face, second); // Get the kerning vector FT_Vector kerning; FT_Get_Kerning(face, index1, index2, FT_KERNING_DEFAULT, &kerning); // Return the X advance return kerning.x >> 6; }
// Load a character glyph Font::Glyph Font::LoadGlyph( char ch, unsigned int size ) { Glyph glyph; // Ensure we can even retrieve the glyph if ( !_fontFace || !SetCurrentSize( size ) ) { return glyph; } // Attempt to load the font's glyph for the given character if ( 0 != FT_Load_Char( _myFontFace, ch, FT_LOAD_TARGET_NORMAL | FT_LOAD_FORCE_AUTOHINT ) ) { return glyph; } // Get the glyph's description FT_Glyph ftGlyph; if ( 0 != FT_Get_Glyph( _myFontFace->glyph, &ftGlyph ) ) { return glyph; } // Rasterize the glyph FT_Glyph_To_Bitmap( &ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1 ); FT_Bitmap& bitmap = reinterpret_cast<FT_BitmapGlyph>( ftGlyph )->bitmap; // Get the glyph's advance glyph.Advance = static_cast<float>( _myFontFace->glyph->metrics.horiAdvance ) * KerningScale; int width = bitmap.width; int height = bitmap.rows; if ( ( width > 0 ) && ( height > 0 ) ) { // Get the glyph's page GlyphPage& page = _pages[ size ]; // Leave a small padding around characters, so that filtering doesn't // pollute them with pixels from neighbors const unsigned int padding = 1; // Find a good position for the new glyph into the texture UintRect emptyArea = FindGlyphRect( page, width + 2 * padding, height + 2 * padding );; // Ensure the texture data is in the center of the texture rectangle emptyArea.X += padding; emptyArea.Y += padding; emptyArea.Width -= 2 * padding; emptyArea.Height -= 2 * padding; glyph.TextureBounds = emptyArea; // Set the glyph's bounding box glyph.Bounds.X = ( _myFontFace->glyph->metrics.horiBearingX ) * KerningScale; glyph.Bounds.Y = -( _myFontFace->glyph->metrics.horiBearingY ) * KerningScale; glyph.Bounds.Width = ( _myFontFace->glyph->metrics.width ) * KerningScale; glyph.Bounds.Height = ( _myFontFace->glyph->metrics.height ) * KerningScale; // Extract the glyph's pixels from the bitmap _pixelBuffer.resize( width * height * 4, 255 ); const unsigned char* pixels = bitmap.buffer; if ( bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) { // Pixels are 1 bit monochrome values for ( int y = 0; y < height; ++y ) { for ( int x = 0; x < width; ++x ) { // The color channels remain white, just fill the alpha channel std::size_t index = ( x + y * width ) * 4 + 3; _pixelBuffer[ index ] = ( ( pixels[ x / 8 ] ) & ( 1 << ( 7 - ( x % 8 ) ) ) ) ? 255 : 0; } pixels += bitmap.pitch; } } else { // Pixels are 8 bits gray levels for ( int y = 0; y < height; ++y ) { for ( int x = 0; x < width; ++x ) { // The color channels remain white, just fill the alpha channel std::size_t index = ( x + y * width ) * 4 + 3; _pixelBuffer[ index ] = pixels[ x ]; } pixels += bitmap.pitch; } } // Write the pixels to the texture page.Texture->UpdateArea( emptyArea.X, emptyArea.Y, emptyArea.Width, emptyArea.Height, &_pixelBuffer[ 0 ] ); } // Cleanup FT_Done_Glyph( ftGlyph ); return glyph; }