Post

C++ SDL Font Install

This guide will provide step-by-step instructions on how to add True Type Font to the Simple DirectMedia Layer (SDL) library in a Visual Studio C++ project.

About True Type Font

TrueType is an outline font standard developed by Apple in the late 1980s as a competitor to Adobe’s Type 1 fonts used in PostScript. It has become the most common format for fonts on the classic Mac OS, macOS, and Microsoft Windows operating systems.

Download SDL True Type Font

Download
  • Unzip the downloaded .zip file
Zip
  • Copy the SDL2 TTF include and lib directory to the existing ThirdParty/SDL2 folder
    • This will add the True Type Font files to SDL2
Zip Zip

Add SDL True Type Font to the Solution Project(s)

If the Solution contains multiple Projects, the following steps will need to be done for each project. This is because each project needs the path to the SDL2 TTF includes and libraries.

Projects

SDL2 should’ve already been setup with the include directories and library directories for the projects, the only step necessary is to add the library (.lib) in the project properties.

Add SDL True Type Font Library

The sdl2_ttf.lib only needs to be added to the project that is the application (Game). Do not add it to the library project (Engine). If it is added to both, there will be a warning reported when built.

  • Open the Project Properties that SDL will be used in
    • Right-click the Project and select Properties
Project Properties
  • Add the SDL2 TTF .lib files that the project needs to function
    • Additional Dependencies is located in Librarian>General or Linker>General
    • Add sdl2_ttf.lib
1
sdl2_ttf.lib
Lib
  • Create a folder in the Solution directory called “Build”
    • This step may have already been completed earlier.
    • The Build folder will contain the SDL TTF dll (dynamic link library) files.
Build
  • Copy the sdl2_ttf.dll file from the ThirdParty\sdl2\lib\x64 directory to the Build folder.
    • The project is a x64 project (64-bit application).
DLL DLL

If SDL2 TT2 was properly added, building and running the project will result in no errors.

Add Fonts to the Build

  • Find fonts to use in the program
Build

Update Code for SDL TTF Fonts

Add TTF Fonts to the Renderer

  • In the Renderer.h header, include the SDL TTF header
1
#include <SDL_ttf.h>
  • Add the code to initialize and quit SDL TTF in the Initialize() and Shutdown() method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool Renderer::Initialize()
{
	// initialize SDL
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		std::cerr << "Error initializing SDL: " << SDL_GetError() << std::endl;
		return false;
	}
	// initialize TTF SDL
	if (TTF_Init() < 0)
	{
		std::cerr << "Error initializing SDL TTF: " << SDL_GetError() << std::endl;
		return false;
	}

	return true;
}
1
2
3
4
5
6
void Renderer::Shutdown()
{
	SDL_DestroyRenderer(m_renderer);
	SDL_DestroyWindow(m_window);
	TTF_Quit();
}

Create Font Class

  • Create Font.h file
1
2
3
4
5
6
7
8
9
10
11
class Font
{
public:
	Font() = default;
	~Font();

	bool Load(const std::string& name, int fontSize);

private:
	_TTF_Font* m_ttfFont{ nullptr };
};
  • Create Font.cpp file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Font::~Font()
{
	if (m_ttfFont != nullptr)
	{
		TTF_CloseFont(m_ttfFont);
	}
}

bool Font::Load(const std::string& name, int fontSize)
{
	m_ttfFont = TTF_OpenFont(name.c_str(), fontSize);
	if (m_ttfFont == nullptr)
	{
		std::cerr << "Could not load font: " << name << std::endl;
		return false;
	}

	return true;
}

Create Text Class

  • Create Text.h file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Text
{
public:
	Text() = default;
	Text(Font* font) : m_font{ font } {}
	~Text();

	bool Create(Renderer& renderer, const std::string& text, const Color& color);
	void Draw(Renderer& renderer, int x, int y);

private:
	Font* m_font{ nullptr };
	SDL_Texture* m_texture{ nullptr };
};
  • Create Text.cpp file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Text::~Text()
{
	if (m_texture != nullptr)
	{
		SDL_DestroyTexture(m_texture);
	}
}

bool Text::Create(Renderer& renderer, const std::string& text, const Color& color)
{
	// create a surface using the font, text string and color
	SDL_Color c{ Color::ToInt(color.r), Color::ToInt(color.g), Color::ToInt(color.b), Color::ToInt(color.a) };
	SDL_Surface* surface = TTF_RenderText_Solid(m_font->m_ttfFont, text.c_str(), c);
	if (surface == nullptr)
	{
		std::cerr << "Could not create surface.\n";
		return false;
	}

	// create a texture from the surface, only textures can render to the renderer
	m_texture = SDL_CreateTextureFromSurface(renderer.m_renderer, surface);
	if (surface == nullptr)
	{
		SDL_FreeSurface(surface);
		std::cerr << "Could not create texture" << SDL_GetError() << std::endl;
		return false;
	}


	// free the surface, no longer needed after creating the texture
	SDL_FreeSurface(surface);

	return true;
}

void Text::Draw(Renderer& renderer, int x, int y)
{
	// query the texture for the texture width and height
	int width, height;
	SDL_QueryTexture(m_texture, nullptr, nullptr, &width, &height);

	// copy the texture onto the renderer
	SDL_Rect rect{ x, y, width, height };
	SDL_RenderCopy(renderer.m_renderer, m_texture, NULL, &rect);
}

Create Text in Main

  • In main() create and load a font
    • Load(True Type Font Filename, Font Size)
1
2
Font* font = new Font();
font->Load("arcadeclassic.ttf", 20);
  • After creating the font, create the text passing the font in the constructor
    • Text(Font)
    • Create(Renderer, Text String, Color)
1
2
Text* text = new Text(font);
text->Create(g_engine.GetRenderer(), "Hello World", Color{ 1, 1, 1, 1 });
  • In the render section of the main loop, draw the text
    • Draw(Renderer, X Position, Y Position)
1
text->Draw(g_engine.GetRenderer(), 40, 40);

Build and run the program and the text will show up on the screen at the set location. Multiple text objects can be created to draw text for player lives and game score.

Lib
This post is licensed under CC BY 4.0 by the author.