I am trying to implement Font Rendering in my OpenGL C++ game.
I read many articles on the subject and got to know different methods, but I am still learning.
Valve has published a paper for Signed Distance Fields and how you can use them with Shaders to generate sharp edges for you text. This has turned out to be the preferred method.
In my project I create all of my characters with Freetype in a loop, bind them to a texture object and reuse them whenever I need a specific character.
I perfectly know that it is not very efficient. Unfortunately, I haven't found a good way to load a bitmap with all the letters and use only single sections. That's why I'm going to use this way for now.
I got everything working (creating the letters, binding the textures and use them for text), but without Signed Distance Fields.
So my Question is how to generate all of my character textures as a Signed Distance Field with the help of Freetype?
This is what my procedure looks like so far:
struct Character {
GLuint textureID, advance;
glm::ivec2 size, bearing;
};
.
FT_Library ft;
if( FT_Init_FreeType( &ft ) )
{
throw std::string( "Could not initialize Freetype Library. Abort" );
}
FT_Face t_face;
if( FT_New_Face( ft, t_fontname.c_str(), 0, &t_face ) )
{
throw std::string( "Could not load " + t_fontname + ". Abort" );
}
// set font size
FT_Set_Pixel_Sizes( t_face, 0, 48 );
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
std::map< GLchar, Character > characters;
for( GLubyte c = 0; c < 128; c++ )
{
// Load character glyph
if ( FT_Load_Char( t_face, c, FT_LOAD_RENDER ) )
{
throw std::string( "Could not load glyph from font. Abort" );
}
// Generate texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D
(
GL_TEXTURE_2D,
0,
GL_RED,
t_face->glyph->bitmap.width,
t_face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
t_face->glyph->bitmap.buffer
);
// Set texture options
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// Now store character for later use
Character character =
{
tex,
t_face->glyph->advance.x,
glm::ivec2( t_face->glyph->bitmap.width, t_face->glyph->bitmap.rows ),
glm::ivec2( t_face->glyph->bitmap_left, t_face->glyph->bitmap_top )
};
characters.insert( std::pair< GLchar, Character >( c, character ) );
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
I already fount this project on github which seems to be a solution. It also depends on Freetype, but to be honest I don't quite understand how the Signed Distance Fields are generated. It might also be too overkill for my intentions.
There are many websites that unfortunately use the old fixed pipeline or are not intended for C++.