Text and fonts

Various fonts in CGE editor Various fonts

1. Show text using a label in user interface: TCastleLabel

The most comfortable way to show text is to use TCastleLabel. You can customize it's font using TCastleUserInterfaceFont.CustomFont and TCastleUserInterfaceFont.FontSize properties.

Many UI controls (see for example unit CastleControls) descend from TCastleUserInterfaceFont, and thus can render text and have their font customized, for example TCastleButton.

You can add and configure UI controls (like TCastleLabel, TCastleButton and many more) by code, or using the CGE editor.

2. Show (potentially 3D) text in a viewport: TCastleText

Another way to render text is to use TCastleText. You can place such component in a viewport and it can be transformed just like any other 3D object.

This is a great way to display text in 3D and/or attach the text to some 3D or 2D game object, e.g. as a debug text over some character.

The properties of TCastleText and TCastleLabel are deliberately very similar. They also use the same font classes underneath.

3. Customizing font

You can add and configure fonts. To customize font in the CGE editor:

  1. Use the "Design -> Add Non-Visual Component" menu item, or the context menu (when you right-click in the hierarchy on the left). Font is added as "Non-Visual Component" to whatever parent you selected.

    The parent that keeps reference to the font node can be anything -- TCastleComponent, TCastleTransform, TCastleUserInterace etc. It is similar to VCL/LCL non-visual components: it doesn't really matter where you drop them on the form.

  2. Then assign this font to TCastleLabel.CustomFont. Or any other UI control descending from TCastleUserInterfaceFont, like TCastleButton or TCastleEdit.

    You can also assign font to TCastleText.CustomFont to customize font used by the (potentially 3D) TCastleText in the viewport.

Our most important font classes:

See examples, e.g. examples/fonts/text_tests for demos of it.

4. Change default font

You can define a default_font inside the CastleSettings.xml file to change the default font. This way CGE editor will also use the new font as default.

5. International characters

Testing local (international) characters

(A complete program using the concepts discussed below is in the engine examples, in the examples/fonts/test_local_characters/. The main code is in gameinitialize.pas unit there. Check it out!)

All font routines (printing, measuring) expect the international characters to be encoded using UTF-8. To draw the international characters (anything beyond basic English ASCII set) you also need to create a font with these characters.

To TCastleFont provide a list of the characters (including all the possible international characters) that you want to display. Like this:

uses ..., CastleFonts, CastleStringUtils;
 
function CreateMyFont: TCastleFont;
begin
  Result := TCastleFont.Create(nil);
  { below is a string containing all my international chars, in UTF-8 }
  Result.LoadCharacters := SimpleAsciiCharacters + '你好世界ΓειασουκόσμεЗдравствуймир';
  Result.OptimalSize := 20;
  Result.Url := 'castle-data:/MyFontFile.ttf';
end;

Make sure to provide the sample characters encoded in UTF-8. In the example above, they are simply hardcoded in the Pascal source file, so make sure that compiler understands it as UTF-8 data. Make sure your source code is in UTF-8 (edit it using an UTF-8 capable editor, consider adding an UTF-8 BOM, consider using {$CODEPAGE UTF8}, see FPC source codepage option).

If you use the texture-font-to-pascal utility to embed fonts in Pascal sources (see above) then use it's parameter --sample-text to provide the additional (beyond simple ASCII) chars. Like this:

texture-font-to-pascal --size 20 MyFontFile.ttf --sample-text '你好世界ΓειασουκόσμεЗдравствуймир'

And make sure that your command-line, and/or your script interpreter, correcly handles UTF-8 (on Linux, this should be a breeze, since everything works with UTF-8 out of the box; on modern Windows it should also work).

6. Localization (translation) using CastleLocalizationGetText

Escape from the Universe (Switch) - Japanese edition

You can use the CastleLocalizationGetText for a localization approach based on GetText.

You use standard GetText formats for translating (PO, MO) and utilizing GetText tools like PoEdit. You can automatically translate strings in Pascal code, declared as resourcestring (use CastleTranslateResourceStrings). You can automatically translate user interface (use TranslateAllDesigns). You can generate starting file to translate user interface (use GenerateGetTextPo).

A typical workflow for translating an application looks like this:

  1. Generate POT (PO Template) files containing everything to translate:

    • Generate POT file to translate the user interface by calling GenerateGetTextPo('castle-data:/gui/*.castle-user-interface');. Place the resulting contents in user_interface.pot.

    • Generate POT file to translate all resourcestrings using the rstconv tool from FPC. Place the resulting contents in game.pot.

  2. Create and translate the PO files for each language you support.

    For each xxx.pot, create a file xxx.<language-code>.po. For example for Polish translation you would create files like game.pl.po and user_interface.pl.po. For Japanese translation you would create files game.ja.po and user_interface.ja.po.

    Note that game.xx.po should contain a map from English text -> localized (Polish, Japanese etc.) text. In contrast, user_interface.xx.po should contain a map from internal identifier (qualified component names) -> localized (Polish, Japanese etc.) text. Both approaches are possible with GetText.

    You can create and edit PO files using any GetText PO editor, like PoEdit. The PO is a text file format, so you can use any regular text editor (like Atom or Emacs) as well.

  3. Generate MO files from PO using the GetText msgfmt tool. Some editors like PoEdit may also do this automatically.

    In effect you will get game.pl.mo, user_interface.pl.mo (Polish translation) and game.ja.mo, user_interface.ja.mo (Japanese translation).

    Place these MO files inside the data directory of your application.

  4. In game, determine user preferred language, e.g. using CastleSystemLanguage.

    Then translate things by loading appropriate MO file.

    • To translate all user interface that will be loaded, call TranslateAllDesigns('castle-data:/translations/user_interface.ja.mo'); (where "ja" stands for Japanese localization, just an example).

    • To translate resourcestrings, call CastleTranslateResourceStrings('castle-data:/translations/game.ja.mo');.

For more details and example how to do it all see the README and source code of our example application using CastleLocalizationGetText (examples/localization/gettext/).

You can tweak this workflow to your needs by using various other routines from CastleLocalizationGetText unit and overriding TCastleComponent.TranslateProperties. You can use more POT / PO files for your own needs. You can translate strings explicitly at any moment, using TMOFile.Translate('my_id').

The engine uses resourcestrings for some internally-generated messages, so these can be translated too.

7. Deprecated

7.1. Explicitly drawing text

NOTE: While this functionality is still available, we advise to rather render all text using TCastleLabel (in UI) or TCastleText (in viewport, maybe in 3D).

Instead of using TCastleLabel, you can explicitly draw the text. For this you need an instance of the TCastleAbstractFont class. To make it easy, one global instance of this class is already created for you: UIFont (part of CastleControls unit). So you can simply draw text like this:

UIFont.Print(10, 10, Yellow, 'Some text to print');

You should place such drawing code inside a render method, for example inside the TCastleWindow.OnRender or TCastleControl.OnRender or inside the overridden TCastleUserInterface.Render implementation. See the manual about 2D drawing for a general info about 2D rendering.

TCastleAbstractFont class has a lot of methods and properties.

7.2. Embed font data in compiled application using texture-font-to-pascal

NOTE: While this functionality is still available, we advise to rather load fonts from TTF / OTF. It is more flexible.

Instead of loading the font data from a file, you can also provide a TTextureFontData instance to the TCastleFont constructor. This allows to create the font data at runtime or to use the font data embedded in a Pascal source code. You can use the texture-font-to-pascal program (compile it from castle_game_engine/tools/texture-font-to-pascal/texture-font-to-pascal.lpr) to convert a font file into a Pascal unit:

texture-font-to-pascal --size 20 MyFontFile.ttf

In response, it will create a unit called CastleTextureFont_MyFontFile_20 with a public function:

function TextureFont_MyFontFile_20: TTextureFontData;

You can use this unit in your program, and create a font instance like this:

MyNewFont := TCastleFont.Create(Application { any TComponent to act as owner });
MyNewFont.Load(TextureFont_MyFontFile_20);

The advantages of embedding a font inside a Pascal unit are:

  • You don't need to distribute the FreeType2 library. (Although this shouldn't be a big problem, CGE can package FreeType2 with your project for all platforms automatically.)
  • Font is loaded slightly faster, since it's already processed to a suitable texture data.

The disadvantages are of course that you cannot simply change the font file anymore, you need to rerun the texture-font-to-pascal command and recompile your program to see the new font.

7.3. Localization (translation) using CastleLocalization

NOTE: This localization approach is deprecated, as it has less features than the GetText approach.

You can use our own localization approach from the CastleLocalization unit. It can read from a number of translation formats (XML, JSON, CSV, GetText MO). It can translate user-interface controls, like TCastleLabel. The demo is inside examples/localization/custom/.

For advanced users, the system allows to aid in localizing your custom classes too (see OnUpdateLocalization) and to add your own translation formats (see FileLoader).

As with GetText approach, you can use a cross-platform CastleSystemLanguage unit that tells you the preferred user language. You can also translate strings "explicitly" using the Localization.Items['my_id'] in CastleLocalization.

Thousand thanks go to Benedikt Magnus for developing this approach!

This localization approach is deprecated. CastleLocalizationGetText offers more features: