ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.03k stars 10.07k forks source link

Unicode and font atlas texture size #918

Open ecraven opened 7 years ago

ecraven commented 7 years ago

I've run into some of the same issues as #307. In the game I'm working on, I don't know which code points will be used. I've tried to render 0x1 to 0xffff, but with several different fonts and font sizes, this does not work on any of the video cards I have access to.

@ocornut you mentioned you were thinking about baking only used characters. What's the status on that? I'd be very interested in dynamically baking the font textures based on which characters are actually used. Is there any way I can help with this?

Alternatively, if this isn't viable, is there a way to do my own font rendering, instead of using any of the baking that imgui has?

ocornut commented 7 years ago

There's no status on that, I've been busy and won't make major imgui improvements until early 2017 at least. If you are urgently interested in those features for localizations you can try digging into the atlas code to improve it, it's fairly simple code.

What you described in #921, to incrementally add new characters over an existing atlas, would be an easy and most useful first step. We need to rewrite ImFontAtlas::Build() in a way that allows incrementally registering/rasterizing new characters. This also means that some data such as the packing context will need to be keep alive along with the atlas. You can start by looking there understanding how this code works.

chetan-prime commented 7 years ago

I'm using IMGUI in a Raspberry Pi via SDL2+GLES2 . Everything is fine except i hit a brick wall trying to support Chinese characters. The RPi GPU has a limit of 2048x2048 sized textures & that isn't enough for 22K characters on a single texture. One possible workaround I was thinking of was patching ImGui to use a vector of textures for single font. So if height goes over our limit it adds one more texture and we shouldn't hit the size limits on a single texture. Is this possible without major changes to the existing ImGui code? I was thinking of dividing by the current total height to know which texture from the vector to use.

ocornut commented 7 years ago

This issue will be best solved by adding a best dynamic atlasing system.

Can you double check that you don't have extraneous oversampling enabled? Reducing it would save your texture usage by up to 4~9.

chetan-prime commented 7 years ago

Thanks for your reply. This is the code I'm using right now ImFontConfig font_config; font_config.OversampleH = 1; font_config.OversampleV = 1; font_config.PixelSnapH = 1; io.Fonts->AddFontFromFileTTF("/usr/share/fonts/truetype/UnDotum/UnDotum.ttf", 24.0f, &font_config, io.Fonts->GetGlyphRangesChinese()); Will full chinese glyphs, my display looks garbled as show in https://github.com/ocornut/imgui/issues/307#issuecomment-134577679

If I set io.Fonts->TexDesiredWidth=2048; and hardset const int max_tex_height = 2048; I can now see Latin characters, but the Chinese characters don't show up as they don't seem to fit within the height constraints/

ocornut commented 7 years ago

Unfortunately this is an open issue at the moment,, and not high priority as the RPi is not a widely used target for imgui.

Your best solution is to compute the characters you need according to your software localization file and only include those characters. This is what most games do.

chetan-prime commented 7 years ago

Thanks, unfortunately I'm using this to display filenames I get off of json from a remote server so I have no way to know what I'm going to show. Since this would be nice for me to get working, would you be fine with a pull request?

I was actually thinking of putting in code that uses an std::map<std::string,struct fontInfo> where fontInfo is new struct. It is then possible to put in code that dynamically loads new glyphs to textures as and when required. This has the advantage of auto-learning and will save a lot of memory and time in initial startup.

ocornut commented 7 years ago

You should check https://github.com/ocornut/imgui/issues/1010 for a better solution.

I would take a serious pull request, but in practice it is likely that a submission would fall the api compatibility, coding style and performances issues of imgui if you are not extra careful and committed to do it right. If you are suggesting to use either std::map + std::string that already very much disqualify the code unfortunately :( I'd be happy to discuss and focus on the feature with you or other people but won't have any time this month. If the link above doesn't lead you to a temporary solution it is reasonable that you attempt to do it yourself and may submit a PR, but please expect me to be very picky (=annoying) with it because it relates to an area where performances requirements are absolutely paramount.

I think the solution discussed by @ecraven is an elegant workaround that is easy to put in place, the only downside is that you will have 1-frame flicker for new characters, but you can always submit your characters to the system as you have them and avoid this 1-frame flicker.

chetan-prime commented 7 years ago

Thanks, #1010 looks like a frugal solution, that uses the existing ImGui code quite nicely. Will test on my end and hope that the delay in loading glyphs once again from the .ttf file isn't very long as the glyphs to load are limited.

towerpark commented 6 years ago

As a workaround, I use the demo propram to load the font (as mentioned here), and try increasing the size_pixels param until all the glyphs can't fit in a N x N altas. Then the last size that fits (if it isn't too small to see) is the max size_pixels for the font on devices that support max texture size of N.

Not a smart solution, just for your reference :)