raysan5 / raylib

A simple and easy-to-use library to enjoy videogames programming
http://www.raylib.com
zlib License
21.41k stars 2.17k forks source link

[rtext] Add support for kerning pairs in font rendering #3716

Closed tromero closed 4 months ago

tromero commented 8 months ago

Issue description

Kerning pairs allow certain pairs of letters to adjust their spacing to aid readability, such as moving the letters in "Av," "At," "To," "Yo" closer together. This data is built into font formats such as ttf and bmfont.

From what I can tell, raylib uses stb truetype to load ttf fonts but discards the kerning pair table it provides and uses a simple single-glyph x advance instead.

It would greatly improve the appearance and readability of text in raylib with non-default fonts if kerning pairs were used when available.

Environment

Emscripten web build, running in Brave browser (chrome, effectively) on an M2 Pro Mac Mini.

Issue Screenshot

Above: raylib. Below: the same text as formatted by my image editor. Screenshot 2024-01-09 at 12 04 42 AM

The font is Roundabout from http://pixel-fonts.com/

Code Example

font = LoadFontEx("resources/fonts/ChevyRay - Roundabout.ttf",  33, nullptr, 0); s_gameTileSet.fontSpacingAdjustment = 1.0f;
DrawTextEx(font, "LToYoTJr.", Vector2{10, 10}, font.baseSize*cameraScale, 1.0f*cameraScale, WHITE);
raysan5 commented 7 months ago

@tromero Supporting kerning-pairs implies redesigning Font structure with all of its consequences, also increasing the complexity and cost of the drawing function to check all kerning pairs on every text draw... I also have doubts if many users really care about it...

I keep the issue open for discussion but the implications are quite high... Probably users requiring that extra text quality shouldn't be using raylib text system and just implement Freetype2 or other advanced text library.

MichaelMackus commented 5 months ago

I have added a library as a proof of concept for this here: https://github.com/MichaelMackus/rltextkerner/

This supports kerning & basic subpixel rendering. The library is mostly a proof of concept, but it seems to work quite well from what I've found. It is much slower due to the kerning, but it can be sped up by caching the bitmaps for each font size (e.g. using the UpdateFontWithKerningBitmaps function).

I'm open to incorporating the code somehow into raylib if you're interested in that. Obviously things can be cleaned up, but I tried to keep the structs somewhat similar to the raylib core ones at least.

I'm just generating an Image in the library, that way I can keep things simple and not worry about drawing directly to the screen since that'd probably be quite slow like you mentioned. I was also not quite sure the best data structure for storing of multiple images for each glyph, I settled on the current version because I found having a large array of images in the main font made the font rendering increasingly slower the more sizes you indexed.

tromero commented 5 months ago

Interesting! Thanks for sharing @MichaelMackus, I'll try to remember to give this a try in my project.

raysan5 commented 4 months ago

I'm closing this issue as out of scope for now. Just as a side note, raylib already considers the advanceX parameter for positioning characters one next to the other, despite not being as precise as kerning-pairs (specific for a glyph-pair), it's good enough for most fonts and use cases.