FeralChild64

TrueType text output for dosbox-automation

Note: This post describes an upcoming dosbox-automation functionality (contributed by me, with some fixes and ideas from @shakeyourbunny), which is already merged to the main GIT branch, but is not yet available to end users. It is intended to be a part of the next major release.

I’ve written the feature without any AI assistance - everything was handcrafted :)

So, what’s this all about? When in text mode, DOSBox takes the font (like 8x16 resolution - very low by today’s standards) from the emulated machine and uses it to construct a bitmap image. Depending on the fork and configuration, post-processing might be applied to make the image look more like a real CRT image:

Norton Commander, VGA font, CRT simulation

Such post-processing (this particular shader was written by John Novak for the DOSBox Staging project, based on some earlier works) is nice for gaming, but prolonged work with such a text console might be tiring.

We can disable the post-processing and enable bilinear filtering instead:

Norton Commander, VGA font, bilinear filtering

But now the font looks blurry and jagged (click the image to zoom).

And here comes the TrueType output - if we set ttf_output = true in the config file, the results are going to look like this:

Norton Commander, default TTF font

The font used here is the Flexi IBM VGA font (https://int10h.org/blog/2018/05/flexi-ibm-vga-scalable-truetype-font/) by @VileR, which is going to be bundled with dosbox-automation. It keeps the style of the old VGA text mode and provides quite a lot of glyphs - we can display around 75 DOS code pages, including probably all the most popular ones.

If you prefer a more modern look, possibly the same as your OS terminal, you can change the font. For example, ttf_font = LiberationMono-Regular (providing that you have this font installed) produces the following image:

Norton Commander, custom TTF font

You can use any TrueType monospace font, but it must contain all the Unicode glyphs needed to display your code page - otherwise dosbox-automation will switch back to classic rendering, and you’ll get a log message telling you about missing glyphs:

[WARN] ttf: Code page 899 cannot be displayed using the current font due to missing glyphs
[WARN] ttf: Missing Unicode official code points:
U+0531, U+0532, U+0533, U+0534, U+0535, U+0536, U+0537, U+0538, U+0539, U+053A, U+053B, U+053C,
U+053D, U+053E, U+053F, U+0540, U+0541, U+0542, U+0543, U+0544, U+0545, U+0546, U+0547, U+0548,
U+0549, U+054A, U+054B, U+054C, U+054D, U+054E, U+054F, U+0550, U+0551, U+0552, U+0553, U+0554,
U+0555, U+0556, U+055A, U+055B, U+055E, U+0561, U+0562, U+0563, U+0564, U+0565, U+0566, U+0567,
U+0568, U+0569, U+056A, U+056B, U+056C, U+056D, U+056E, U+056F, U+0570, U+0571, U+0572, U+0573,
U+0574, U+0575, U+0576, U+0577, U+0578, U+0579, U+057A, U+057B, U+057C, U+057D, U+057E, U+057F,
U+0580, U+0581, U+0582, U+0583, U+0584, U+0585, U+0586, U+058A, U+058E

One might think the implementation of such a feature should be easy and straightforward - well, it is not :)

One challenge is converting the DOS characters (values from 0 to 255, values have different meaning depending on the code page) to the modern Unicode character set (the Unicode standard currently defines over 300,000 characters) - in reality, a specialized Unicode engine is needed for this, as off-the-shelf ones have a very limited support for DOS code pages. Thankfully, the one dosbox-automation uses (written by me a few years ago, supporting over 170 unique DOS code pages, plus some duplicates) only needed some really minor tweaks to be usable.

Certain exotic code pages need a character composition engine able to render characters by combining a base glyph with separate combining marks code points; the current implementation can’t do this (sorry, Lithuanians…) - this might get implemented one day, we’ll see.

Another challenge is the performance - a 80x25 screen mode means up to 2000 vector characters needs to be rendered 70 times per second. This is a lot, especially for modern high resolution (like 4K or even more) displays.

Various optimization techniques are used to speed it up - once the window resolution is established, all the 256 current code page characters are pre-rendered in greyscale to save time later. Applying the foreground/background colors happens in a way which makes it easy for the compiler to use the specialized SIMD (like Intel SSE or ARM Neon) CPU instructions. Plus, line caching is involved (if the color palette is unchanged, we just need to compare two bytes to check if the particular screen character is up to date) to limit the unnecessary character redraw.

This way, the performance is acceptable for normal work (some special cases, like the BB demo, make the line caching useless), though still inferior to the classic rendering.

And that’s still not everything - you can’t just let a TrueType engine (the implementation uses the FreeType library) render the character and assume everything is going to be correct. With the bundled font, this is mostly the case, but for other popular fonts… let’s see one example:

Norton Commander, TTF corrections disabled

The dosbox-automation implementation (just like every modern terminal application) has some measures to prevent such gaps (resulting from anti-aliasing or font design) and certain other visual artifacts from appearing.

It should be able to do the job most of the time, but still has some limitations. For some fonts, the shade characters (U+2591, U+2592, U+2593 - ░, ▒, ▓, respectively) won’t look right when placed one next to another, and probably not much can be done about it.

In a few cases (ligatures, hryvnia currency sign, etc.), the TrueType output can render the characters even if they are missing in the selected font, by combining characters which are available. Results might vary depending on the font and the character, but at least the code page can be supported. For some code pages this is the only realistic way to handle them, as they use characters not present in the Unicode standard - I had to assign private Unicode IDs to such DOS characters.

See the character 0x9B below (a zł ligature) - this is the PLN currency symbol, as found on some old typewriters, not covered by the Unicode standard, drawn by cramping two characters together:

DOS code page 991, TTF font

Another issue which has to be handled - some text mode DOS applications redefine the screen font, so that their user interface is richer.

If we blindly replace such redefined font, we are going to get a screen containing garbage characters:

Tetepack, garbage font

while the proper appearance of the application is:

Tetepack, correct image

To prevent such issues, the TrueType output code observes writes to memory areas which define the screen font. If it detects that the screen font is altered, it reverts to the normal, old-style rendering method, for as long as the screen font remains modified - afterwards it returns to the TrueType output. Same happens when a custom CPI file (DOS format screen font) is loaded.

Last, but not least - we have a few aspect ratio settings to choose from (see the ttf_aspect option). You can force the 4:3 screen proportions, use the selected TrueType font aspect ratio, or expand the image in a widescreen-friendly way, trying to preserve the character aspect ratio from the standard 80x25 screen mode, like below (DOS Navigator OSP 6.4.0 using a 94x25 resolution):

DOS Navigator, TTF font, widescreen

And here is the BB demo in high resolution:

BB demo, TTF font, widescreen

The aspect = stretch setting is also honored - you can make the text mode fill the entire window/screen.

That’s all, folks! Have fun with it once the feature is released!