Skip to content
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

Pre-baked font atlas? #2093

Closed
YukinoHayakawa opened this issue Sep 18, 2018 · 9 comments
Closed

Pre-baked font atlas? #2093

YukinoHayakawa opened this issue Sep 18, 2018 · 9 comments

Comments

@YukinoHayakawa
Copy link

I have a huge range of characters to be displayed (several K Asian characters), each time imgui takes about 5~8 seconds to build the atlas in debug version. Since I always use the same font with the same Unicode ranges, I hope there is some way of caching the built atlas so next time the font baker only need to build coordinates. Is this trivially possible? It replacing ImFontAtlasBuildWithStbTruetype the only choice? Thanks in advance.

@ocornut
Copy link
Owner

ocornut commented Sep 18, 2018

It's not trivially possible yet.

Maybe the imgui_freetype/ renderer would be faster I don't know?

Other workarounds:

  • Generally what is mostly highly recommended is to only build for the characters you need (using the GlyphsRangeBuilder). It may apply or not depending on the nature of your project.
  • You may also reduce Oversample which would reduce the output resolution which affects the building speed.
  • Configure your project to always compile imgui files in a more optimized way or at least not with the default Debug settings that Visual Studio uses (if you are using Visual Studio): their default security checks are extremely aggressively slow. For reference, building and rasterizing the entire GetGlyphRangesChineseFull() range (~22000 glyphs) with Arial Unicode size 18 px takes 1.5 seconds in reasonable-Debug-settings on my laptop.

It would also be possible to add a ImFontAtlasFlags flag to disable the rasterization process but you'll have to provide the texture data on your side.

@YukinoHayakawa
Copy link
Author

YukinoHayakawa commented Sep 19, 2018

Actually I have thought of the third workaround and now I gave it a try... The result was quite impressive. First I have to apologize for my awful sense of time since a debug build actually took only ~3.5s to build the atlas. Merely turning off the runtime check cut the time in half. Together with /O2 it took only 0.6sec on my machine. It's a totally acceptable time now! Here is my test result:

Default Debug Config (3.5s)

[2018-09-19 13:16:50.227] [console] [info] ImGui: Start building font atlas
[2018-09-19 13:16:53.778] [console] [info] ImGui: Finish building font atlas

Basic Runtime Checks = Default (1.5s)

[2018-09-19 13:15:44.604] [console] [info] ImGui: Start building font atlas
[2018-09-19 13:15:46.187] [console] [info] ImGui: Finish building font atlas

Basic Runtime Checks = Default + O2 (0.6s)

[2018-09-19 13:18:25.419] [console] [info] ImGui: Start building font atlas
[2018-09-19 13:18:26.052] [console] [info] ImGui: Finish building font atlas

For the other two workarounds, the first is generally not possible since user input unpredictable. The "common" Chinese character range is almost useless, at least for our project... Because being common for the whole Chinese world does not necessarily means being common for used in games, not to say a particular game. I actually included more glyphs than GetGlyphRangesChineseFull, which even don't have some common full-width punctuation. Here is my ranges (we are developing a visual novel):

static const ImWchar RANGES[] =
{
    0x0020, 0x007F, // Basic Latin
    0x00A0, 0x00FF, // Latin-1 Supplement
    0x2000, 0x206F, // General Punctuation
    0x3000, 0x303F, // CJK Symbols and Punctuation
    0x3040, 0x309F, // Hiragana
    0x30A0, 0x30FF, // Katakana
    0x31F0, 0x31FF, // Katakana Phonetic Extensions
    0x4E00, 0x9FFF, // CJK Unified Ideographs
    0xFF00, 0xFFEF, // Halfwidth and Fullwidth Forms
    0,
};

Compared with bulit-in ranges:

const ImWchar*  ImFontAtlas::GetGlyphRangesChineseFull()
{
    static const ImWchar ranges[] =
    {
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
        0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
        0x31F0, 0x31FF, // Katakana Phonetic Extensions
        0xFF00, 0xFFEF, // Half-width characters
        0x4e00, 0x9FAF, // CJK Ideograms
        0,
    };
    return &ranges[0];
}

Closing the issue :)

@ocornut
Copy link
Owner

ocornut commented Sep 19, 2018

Do you think we should add those blocks (at least) into the chinese ranges?

    0x2000, 0x206F, // General Punctuation
    0x3000, 0x303F, // CJK Symbols and Punctuation

I think I ought to document better and suggest more people to use the GlyphRangeBuilder, as it makes it easier to just add things to do when you need.

@ocornut
Copy link
Owner

ocornut commented Sep 19, 2018

For a novel game you should presumably know ahead of time what the vast majority of your text contents is, and this is what the glyph range builder is used for.

Assuming you have user-driven textual input you could create a dynamic font atlas dedicated to hold ONLY the user characters (so it is smaller), and rebuild only this atlas on the new frame. An odd but workable trick is to skip rendering once when you rebuild the atlas, because it the new characters can only be rebuild before NewFrame(). So when you stumble on an unknown character, add it to the glyph range builder, skip render and mark the atlas for rebuilding at the beginning of next frame. Tada, you have a dumb dynamic atlas. If your user-driven text is stuff like "character name" it should be ok to do that (not ok if your use case is more like "1000 online users typing into a chat box and sharing text").

Down the line the atlas system should allow for incremental build.

There's also an issue with deciding on the texture width ahead of the building which might lead to large texture height (amusingly nuklear which cloned several things from imgui pulled in the same issue from an old version of imgui. it is slightly less worse in imgui now) but you can set atlas->TexDesiredWidth to the maximum available width on your GPU to overcome that.

@YukinoHayakawa
Copy link
Author

Those two ranges you quoted cover several kinds of quotation marks and dashes and others, which are quite common in novels. I think players won't be using them too much, but adding them might not be a bad idea to prevent the confusion caused by can't type a simple Chinese period.

The dynamic atlas method sounds very interesting to me. As you mentioned nuklear, I'm actually using both imgui and nk at the same time. I'm trying to get some skinned windows out of it (not done yet). I already filled an issue for nk for its texture width problem as the texture height it produced did exceed my GPU limit with moderately large font sizes.

Apart from the two GUI libraries, I also have to handle text rendering for character dialogs, which may have different fonts & sizes than the GUI, and may need some effects such outlines. But the glyph ranges generally remain the same. So I've been thinking of a font system supporting dynamic atlas for the whole game, but I don't have any good ideas for that yet. This is largely my personal need and is not related with this issue anyway.

@ocornut
Copy link
Owner

ocornut commented Sep 19, 2018

For in-game text rendering if you don't need the full UI side of things, you would probably be better off using FontStash https://github.com/memononen/fontstash

@YukinoHayakawa
Copy link
Author

Now I learnt a new phrase "online atlas builder" :) Looks great to me, I'll look into it when I start dealing with text rendering. Thank you very much!

@sgf
Copy link

sgf commented Jan 6, 2019

In fact, it needs to do a dynamically loaded and make a Cache(last update by use times) to resolve.

ocornut added a commit that referenced this issue Jan 17, 2019
… ChineseFull/ChineseSimplifiedCommon ranges. (#2093)
@ocornut
Copy link
Owner

ocornut commented Mar 6, 2025

I have a huge range of characters to be displayed (several K Asian characters), each time imgui takes about 5~8 seconds to build the atlas in debug version.

FYI, work on dynamic_fonts branch aimed to be merged in 1.92 (#8465) solves this, as glyphs are rasterized and packed on demand when they are used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants