-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Truetype support #202
base: main
Are you sure you want to change the base?
Truetype support #202
Conversation
Create a fonts folder in the root directory, then add the corresponding folders according to the language, such as chs, english, and then create an ini file with the following content: [font0] [font1] [font2]...etc The encoding value refers to the support for encoding in libiconv Then put the corresponding ttf font file in the directory. If there is an error in this process, the font is displayed in the old way. |
Tested on Arch linux and it works great. Amazing job! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few recommendations on how could the implementation be improved.
{ | ||
if (input[0] == '\x95') { | ||
size_t output_size = 1024; | ||
iconv_t cd = iconv_open("UCS-4-INTERNAL", current->encoding); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UCS-4-INTERNAL is not available on various systems, e.g. Ubuntu 20.04. UCS-4-INTERNAL could either be UCS-4LE or UCS-4BE. Is it guaranteed that UCS-4BE encoded unicode charcodes are understood by FT_Get_Char_Index()
?
char* tmp = (char*)(output + 1); | ||
const char* tmp2 = (const char *)(input + 1); | ||
charInPutLen -= 1; | ||
iconv(cd, &tmp2, &charInPutLen, &tmp, &output_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if cd is -1 (iconv_open failed).
|
||
static int LtoU(const char* input, size_t charInPutLen) | ||
{ | ||
if (input[0] == '\x95') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opening and closing iconv cd at each function call is slow. It would be much better if the iconv object would be opened at the time when the font is loaded and closed when the font manager deletes the font. The cd could be stored in the font specific descriptor.
iconv can reset the conversion state by passing it nul parameters so there is really no need to open and close the converter at each call.
You can also create a dedicated LtoU and another UtoL instance.
current->map[unicode].rows = knobHeight; | ||
current->map[unicode].buffer = knobDump; | ||
} else { | ||
FT_Load_Glyph(current->face, FT_Get_Char_Index(current->face, unicode), FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if FT_Get_Char_Index
returns undefined character code. What happens if the face does not load the glyph and FT_Load_Glyph
returns an error in which case it might be nondeterministic what would be rendered by FT_Render_Glyph
?
// 0x441CEC | ||
void FtFontsExit() | ||
{ | ||
for (int font = 0; font < FT_FONT_MAX; font++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I am not mistaken, you never called FT_Done_Face
. Resources of all loaded fonts are possibly leaked. Ah ok, I just realized the todo below.
// 0x441D20 | ||
static int FtFontLoad(int font_index) | ||
{ | ||
char string[56]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In proper ttf fonts the horizontal bearings and the advance are all encoded in the glyph metrics. These manually set up, resolution specific settings from the ini files can all be calculated for the requested em size on the fly. Both maxWidth and maxHeight could be iteratively found for a particular em size without rendering using FT_Get_First_Char
and FT_Get_Next_Char
in a while loop at font load time.
ptr += 10000; | ||
} | ||
|
||
if (fileRead(ptr, 1, readleft, stream) != readleft) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this fails, what happens with desc->filebuffer ? Is it cleaned up by the caller?
} | ||
|
||
FT_Init_FreeType(&(desc->library)); | ||
FT_New_Memory_Face(desc->library, desc->filebuffer, fileSize, 0, &desc->face); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if these APIs return non 0, any error?
} | ||
|
||
unsigned char* palette = _getColorBlendTable(color & 0xFF); | ||
int count = LtoU((char*)string, strlen(string)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there is outline (FONT_SHADOW) than LtoU is prcessing entire strings twice.
GNW based GUI implementations often center align vertically or horizontally in which case the current implementation will call LtoU
or UtoL
for the exact same string several times.
It would make sense to cache the generated strings and free them up when they become stale in the cache. This could increase overall performance a lot.
FtFontDrawImpl(buf + pitch + 1, string, length, pitch, (color & ~0xFF) | _colorTable[0]); | ||
} | ||
|
||
unsigned char* palette = _getColorBlendTable(color & 0xFF); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Building these blend tables are expensive. The GNW implementation I seen uses a reference counted lookup table and free up a particular blend table when the ref count reaches 0. In this context a blend table is built for (color & ~0xFF) | _colorTable[0])
and another for color & 0xFF
. As there are but a few text colors, like green, golden, etc. it would make sense to simply generate these blend tables for the most common text colors in the init phase and add reference counters to them. On exiting the font manager, _freeColorBlendTable
could be called as many times as the text manager reference count value.
|
@klei1984 |
Nice to see this. However I disappointed in this approach the size of glyphs is too small. Any custom font looks awful. And many menus elements doesn't support custom size of glyphs. For exmple in dialogs you cannot scroll your answers list. |
I integrated the given solution into GNW in the M.A.X. Port project trying to resolve all code review findings that are noted here. M.A.X. had a C++ wrapper on top of GNW for its basic UI elements like windows, edit controls, buttons, text boxes. The C++ layer manages various resources, including audio samples, but it does not handle automatic label formatting and resizing. Truncation of non fitting text is supported. The implementation of the TTF GNW font manager in M.A.X. Port can be found here. Please note that M.A.X. does not use monochromatic AAF fonts, so GNW Color's blending tables are not supported in the given implementation. Based on the review comments it can be integrated with relative ease. |
c4e35dc
to
83a6118
Compare
Will this project still be updated? |
Hello, I added truetype font support for Fallout 2, which makes it easy to support multiple languages.
Support to adjust the font size and replace different ttf fonts.
Use iconv to convert the encoding, and then read the glyphs through the freetype library.
Windows, android, ios, macos have been tested, but linux platform has not been tried.