True Type Fonts
Last Updated: Oct 2nd, 2024
Here we're going to show text from TTF fonts using the SDL_ttf library./* Headers */ //Using SDL, SDL_image, SDL_ttf and STL string //Using SDL and STL string #include <SDL3/SDL.h> #include <SDL3/SDL_main.h> #include <SDL3_image/SDL_image.h> #include <SDL3_ttf/SDL_ttf.h> #include <string>
Make sure to have SDL_ttf installed and configured in your project and don't forget to include the SDL_ttf header.
/* Class Prototypes */ class LTexture { public: //Symbolic constant static constexpr float kOriginalSize = -1.f; //Initializes texture variables LTexture(); //Cleans up texture variables ~LTexture(); //Loads texture from disk bool loadFromFile( std::string path ); #if defined(SDL_TTF_MAJOR_VERSION) //Creates texture from text bool loadFromRenderedText( std::string textureText, SDL_Color textColor ); #endif //Cleans up texture void destroy(); //Sets color modulation void setColor( Uint8 r, Uint8 g, Uint8 b); //Sets opacity void setAlpha( Uint8 alpha ); //Sets blend mode void setBlending( SDL_BlendMode blendMode ); //Draws texture void render( float x, float y, SDL_FRect* clip = nullptr, float width = kOriginalSize, float height = kOriginalSize, double degrees = 0.0, SDL_FPoint* center = nullptr, SDL_FlipMode flipMode = SDL_FLIP_NONE ); //Gets texture dimensions int getWidth(); int getHeight(); private: //Contains texture data SDL_Texture* mTexture; //Texture dimensions int mWidth; int mHeight; };
We're going to be adding the
If you're wondering what that
loadFromRenderedText
which creates a texture from the string/color we provide it.If you're wondering what that
#if defined(SDL_TTF_MAJOR_VERSION)
does, it checks if SDL_TTF_MAJOR_VERSION
is defined which happens when we include SDL_ttf. This is a way to easily exclude the TTF rendering code from the LTexture
because when we don't include
SDL_ttf.h, SDL_TTF_MAJOR_VERSION
is not defined and it will omit the code sandwiched in the #if defined
block. This is an example of a macro (using #include
is also a macro) which is code that talks to the compiler.
/* Global Variables */ //The window we'll be rendering to SDL_Window* gWindow{ nullptr }; //The renderer used to draw to the window SDL_Renderer* gRenderer{ nullptr }; //Global font TTF_Font* gFont{ nullptr }; //The texture we're going to render text to LTexture gTextTexture;
We have a new data type for our TTF font file we're going to load: TTF_Font.
#if defined(SDL_TTF_MAJOR_VERSION) bool LTexture::loadFromRenderedText( std::string textureText, SDL_Color textColor ) { //Clean up existing texture destroy(); //Load text surface if( SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor ); textSurface == nullptr ) { SDL_Log( "Unable to render text surface! SDL_ttf Error: %s\n", SDL_GetError() ); } else { //Create texture from surface if( mTexture = SDL_CreateTextureFromSurface( gRenderer, textSurface ); mTexture == nullptr ) { SDL_Log( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() ); } else { mWidth = textSurface->w; mHeight = textSurface->h; } //Free temp surface SDL_DestroySurface( textSurface ); } //Return success if texture loaded return mTexture != nullptr; } #endif
Creating a texture from text works much like doing so from a file, but instead of calling
SDL_LoadBMP
or IMG_Load
to generate the surface, you can use TTF_RenderText_Solid. As you can see, it otherwise
works mostly the same as it does with loading from a file.TTF_RenderText_Solid
is the simplest and fastest way to render a surface from text. There are other ways you can check out in the SDL_ttf documentation.
/* Function Implementations */ bool init() { //Initialization flag bool success{ true }; //Initialize SDL if( !SDL_Init( SDL_INIT_VIDEO ) ) { SDL_Log( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() ); success = false; } else { //Create window with renderer if( !SDL_CreateWindowAndRenderer( "SDL3 Tutorial: Color Modulation and Blending", kScreenWidth, kScreenHeight, 0, &gWindow, &gRenderer ) ) { SDL_Log( "Window could not be created! SDL_Error: %s\n", SDL_GetError() ); success = false; } else { //Initialize PNG loading int imgFlags = IMG_INIT_PNG; if( !( IMG_Init( imgFlags ) & imgFlags ) ) { SDL_Log( "SDL_image could not initialize! SDL_image error: %s\n", SDL_GetError() ); success = false; } //Initialize font loading if( !TTF_Init() ) { SDL_Log( "SDL_ttf could not initialize! SDL_ttf error: %s\n", SDL_GetError() ); success = false; } } } return success; }
Much like how we have to initialize SDL_image with
IMG_Init
, we need to initialize SDL_ttf with TTF_Init.
bool loadMedia() { //File loading flag bool success{ true }; //Load scene font std::string fontPath = "08-true-type-fonts/lazy.ttf"; if( gFont = TTF_OpenFont( fontPath.c_str(), 28 ); gFont == nullptr ) { SDL_Log( "Could not load %s! SDL_ttf Error: %s\n", fontPath.c_str(), SDL_GetError() ); success = false; } else { //Load text SDL_Color textColor = { 0x00, 0x00, 0x00, 0xFF }; if( !gTextTexture.loadFromRenderedText( "The quick brown fox jumps over the lazy dog", textColor ) ) { SDL_Log( "Could not load text texture %s! SDL_ttf Error: %s\n", fontPath.c_str(), SDL_GetError() ); success = false; } } return success; }
To open up a TTF font file we call TTF_OpenFont and pass in the path to the font and the size we want to render the font.
void close() { //Clean up textures gTextTexture.destroy(); //Free font TTF_CloseFont( gFont ); //Destroy window SDL_DestroyRenderer( gRenderer ); gRenderer = nullptr; SDL_DestroyWindow( gWindow ); gWindow = nullptr; //Quit SDL subsystems TTF_Quit(); IMG_Quit(); SDL_Quit(); }
When we're done with a font, we free it with TTF_CloseFont. When we want to close SDL_ttf, we call TTF_Quit.
//Fill the background SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); SDL_RenderClear( gRenderer ); //Render text gTextTexture.render( ( kScreenWidth - gTextTexture.getWidth() ) / 2.f, ( kScreenHeight - gTextTexture.getHeight() ) / 2.f ); //Update screen SDL_RenderPresent( gRenderer );
Finally, here we render the text texture we loaded.
SDL_ttf has other method of rendering text which you can find in the SDL_ttf documentation. We'll be covering some of them in future tutorials, I just wanted to get started with this one because it's the easiest if you already know how to render SDL textures.
SDL_ttf has other method of rendering text which you can find in the SDL_ttf documentation. We'll be covering some of them in future tutorials, I just wanted to get started with this one because it's the easiest if you already know how to render SDL textures.