Video Engine Text

From Hero of Allacrost Wiki
Jump to: navigation, search


The text sub-system in the video engine manages all text and font related operations for rendering text to the screen. Its primary purpose is to support the use of TrueType font (TTF) files and the rendering of unicode text strings. Standard string types may also be drawn (they are first converted to unicode strings and then rendered, so they are slower to render). The name of the principle class in this sub-system is TextSupervisor, which is a singleton class and goes by the singleton object name TextManager. The other public classes are TextStyle, which is a simple container used to set various properties in several function calls, and RenderedText, which is text that has been rendered to texture memory and resides there, allowing it to be drawn as if it were a standard image.

Text Shadows[edit]

Appropriate use of text shadows allow text to be much more visually appeasing to the viewer. There are several different types of shadow styles, as the image below exemplifies.

Video engine text shadows.png

In addition to a style, you can also declare an x and y offset for shadows to make them larger or smaller. These offsets are in terms of pixels. A positive x offset will move the shadow to the right of the text while a negative x offset moves the shadow left of the text. With y offsets, positive moves the shadow up, while negative moves the shadow down. Note that a shadow is nothing more than a duplicate render of the text drawn in a color that is different than the text's color. The shadow is drawn first, then the text on top of it. For this reason, having x and y offsets that are both zero makes no sense because the shadow will be completely drawn over by the text. For this reason, it is invalid to set shadow offsets to (0, 0). One shadow coordinate may be zero as long as the other is non-zero, however.

Default Properties[edit]

The TextSupervisor class retains two default properties for text: the default font to use, and a default color to render the text in. These defaults are used when the user specifies to draw a piece of text, but did not specify the specific properties to render the text in. The defaults are also used as a failsafe in the case that the user supplied incorrect properties (for example, requesting a font name for which no font existed). Every loaded font has several default properties of its own. These include: the text shadow style to use and the x and y shadow offset values. Whenever either of these properties are not specified in a draw operation, the font which is used to render the text will apply its default shadow properties to the rendering. There are other properties specified for a font (such as the amount of space between horizontal lines of text, a property specified by the font itself), but those are not mutable by the user, so we ignore them here.

In summary, below are the list of default properties which the user may change at will. Be careful about relying on the default properties being some value, as these defaults can be changed at anytime by any block of code.

  • Default font
    • Font's default shadow style
    • Font's default shadow offsets (x and y)
  • Default text color


It is recommended practice to refer to the TextManager singleton object through the GameVideo class via the following call.

GameVideo::TextSupervisor* Text(); // returns a pointer to the TextManager singleton

This call is guaranteed to return a valid pointer so long as the video engine was successfully initialized. The following is a typical example of invoking a text operation.

VideoManager->Text()->Draw("Hello, world!");

Font Management[edit]

The text sub-system defines a "font" to be a combination of data loaded from a valid font file paired with a desired font size. Thus a font file named "courier.ttf" loaded at 12 point size and the same file loaded at 18 point size are treated as if they are two entirely different fonts. Fonts are identified by an identifier name given to the font when it is loaded via the following call.

// Function signature
bool TextSupervisor::LoadFont(const std::string& filename, const std::string& font_name, uint32 size, TEXT_SHADOW_STYLE style = VIDEO_TEXT_SHADOW_NONE, int32 x_offset = 0, int32 y_offset = 0, bool make_default = false);

// Example use
if (VideoManager->Text()->LoadFont(“img/fonts/my_font.ttf”, “cool”, 18) == false) {
    PRINT_ERROR << "failed to load font file img/fonts/my_font.ttf" << endl;

The font_name argument is the unique name that will hereafter be used to identify the font, so long as it is loaded successfully. The font name "debug_font" is reserved by the video engine for its own display of debugging information, such as FPS or other diagnostics. The size argument must be greater than zero or the call will fail. The remaining arguments are optional. They set the shadow style and shadow offsets for the font, respectively. If the default shadow offsets are used (0, 0), the shadow offset will actually be set to 1/8th of the maximum glyph height for the font in the right and downwards direction (a 0, 0 offset for a shadow makes no sense, because the text itself would fully cover its shadow). The final argument, if set to true, will mark this font as the default to use in the TextManager, so long as the call completes successfully.

Once you are finished using a particular font, you may wish to free it to avoid consuming unnecessary resources. This is actually a rare case, sense you would normally continue to use a font throughout the operation of the game at specific points.

void TextSupervisor::FreeFont(const std::string& font_name);

You may set the default font at any time, or get the name of the current default at will.

const std::string& TextSupervisor::GetDefaultFont() const;
void TextSupervisor::SetDefaultFont(const std::string& font_name);

If you wish to change the default shadow style or offsets of a particular font, there are calls which support that as well. Note that it is impossible to change the size of a loaded font at will (if you truly desire this, free the font and then reload it at the desired font size).

void TextSupervisor::SetFontShadowStyle(const std::string& font_name, TEXT_SHADOW_STYLE style);
void TextSupervisor::SetFontShadowOffsets(const std::string& font_name, int32 x, int32 y);

Text Management[edit]

You may modify or retrieve the default color to render text in via the following two methods.

Color TextSupervisor::GetDefaultTextColor() const;
void TextSupervisor::SetDefaultTextColor(const Color& color);

The TextSupervisor class contains low-level text drawing functions. These functions draw a specified screen of text on the screen using the current position of the draw cursor and the draw alignment flags which are set. It is recommended to avoid using these functions wherever possible, as they will re-render the string everytime that it is drawn to the frame. This can be a very expensive operation, especially with large amounts of text. They also do not support any advanced features, such as gradual display of the text to the screen (this is done with the TextBox class available in the GUI sub-system). As was noted earlier, drawing of std::strings is a more costly operation than using a ustring (unicode string), as they will first be converted to a ustring object and drawn only then.

void TextSupervisor::Draw(const hoa_utils::ustring& text);
void TextSupervisor::Draw(const std::string& text);

The methods which only take a text argument use all the default font and text properties that are currently set. You may set any of the available text properties (font, color, shadows, etc.) by passing a reference to a TextStyle object. (The TextStyle class will be explained in the following section).

void TextSupervisor::Draw(const hoa_utils::ustring& text, const TextStyle& style);
void TextSupervisor::Draw(const std::string& text, const TextStyle& style);

Finally, it is possible to calculate what the width of a rendered string (in pixels) would be before actually rendering it through either of the following calls. A negative value is returned if there is a problem with either argument that is passed to the function.

int32 CalculateTextWidth(const std::string& font_name, const hoa_utils::ustring& text);
int32 CalculateTextWidth(const std::string& font_name, const std::string& text);


(to be written)


If a piece of text is to be drawn repeatedly (ie. each frame), its expensive to construct it every time with the DrawText() function. Text can be rendered to an object for repeated rendering.

VideoManager->SetTextColor(Color(1.0f, 1.0f, 0.0f, 0.8f); // 80% translucent yellow text 
RenderedString *string = VideoManager->RenderText(MakeUnicodeString("Hello more permanent world"));

VideoManager->Move(x, y);

Note that all Font/Color/Shadow style changes made after the text is rendered will not affect rendered text.