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

Dynamically changing font size #797

Open
b1tc0der opened this issue Aug 24, 2016 · 25 comments
Open

Dynamically changing font size #797

b1tc0der opened this issue Aug 24, 2016 · 25 comments

Comments

@b1tc0der
Copy link

I have an application that I am currently porting from NanoVG to ImGui. The application allows for (an unlimited amount of) different text sections and each section can have a different font size.
As far as i understand NanoVG retrieves each glyph on demand and creates it at the requested font size which makes for really crisp output for large fonts.
In ImGui it seems that I have to reload the font from the ttf file whenever I want to change the font size.
The ImGui sample app shows how to use the in-built font scaling, but even at x2 the font becomes really blurry; is there any way around that?
Reloading the font dynamically works fine if there are not many text sections that use a different font sizes, but loading the same font for each used font size is not manageable.

This is not meant as criticizing ImGui; far from it; I love ImGui and I'll be using it for all my projects from now on. Just wondering how I could implement this.
Thanks :-)

@ocornut
Copy link
Owner

ocornut commented Aug 24, 2016

Sorry this is not yet handled by the atlas system. It will eventually be added but it's not a high-priority task (and yes, I have heard a million times of FontStash :).

Workarounds

  • Bake multiple sizes into the atlas and select the best one+appropriate scale in your app (I realize this is quite annoying).
  • Note that you can enable Oversampling during baking + bilinear mag/min on your texture sampler, scaling will be a little better with both. But of course you are still scaling bitmaps there, no magic. Baking at 30px and using that at 0.5 and 1 scale will obviously be better than baking at 15px and using at scale 1 and 2.

@b1tc0der
Copy link
Author

I'll try your suggestions in the mean time, thanks :-)
Has anyone offered to help implement fontstash? Or do you prefer to do it yourself?
This is a semi-urgent issue for me and I might have to do it for my code base anyway.
I'd be happy to help.

@ocornut
Copy link
Owner

ocornut commented Aug 25, 2016

Fontstash isn't appropriate because it does too many things and I would like to finetune the code for perfs because CalcTextSize calculation loop is a bottleneck for large ui.

Basically the code in ImFontAtlas::Build() has to be refactored, parts extracted so packing/rasterizing can occur iteratively. While refactoring this we could also make it easier to integrate external font loader e.g. #618

In CalcTextSize() we can replace lines such as const float char_width = ((int)c < IndexXAdvance.Size) ? IndexXAdvance[(int)c] * scale : FallbackXAdvance; to handle missing glyphs according to font size. This code is quite bottleneck (this is why there is a hot-dense IndexXAdvance[] array instead of poking in Glyphs). ImFont probably needs to be also reworked to store multiple sizes? I'm not sure where all this data will go yet.

If you are eager to look into it feel free to do so and I can help (but I'll be quite tedious :)

It's not that much work, I think I could do it the way I'd like in 2 days but I don't have that time right now.

@ocornut
Copy link
Owner

ocornut commented Sep 5, 2016

Also see @thedmd hack here. Not exactly trivial nor cheap but might be worth trying if other workarounds are satisfactory for now.
#772 (comment)
#772 (comment)

node_preview_4
ImGui can be bend to handle zooming while keeping crisp details.
image

@sgf
Copy link

sgf commented Jun 18, 2017

seems thedmd use load a big font size and most of UI font Scaled to small to use .....

@maxon887
Copy link

also requested

@OvermindDL1
Copy link

Adding support for SDF style fonts would allow for pretty arbitrary scaling without blurriness or expensive memory cost if a good SDF style font is used.

@thedmd
Copy link
Contributor

thedmd commented Oct 27, 2017

@sgf I'm using two font sizes, one with normal size and one with 4 x normal size when zooming.

@maxon887
Copy link

Yes me to, but it's kind of a hack. Really you don't need second texture which 4 times larger (and and switch them at run time).

@thedmd
Copy link
Contributor

thedmd commented Oct 27, 2017

They are on very same texture. I'm just calling AddFontFromFileTTF twice before building atlas. And this hack is no different than using two fonts with different styles.

@Flix01
Copy link

Flix01 commented Oct 27, 2017

@OvermindDL1: I've made some experiments with signed distance fonts in my fork, and in the gist I've linked here: #889 (BTW: they're not a font style, but a different way to display fonts).

They are good, but I have experienced the following drawbacks:

  • They require a specialized shader (they don't work without shader support, even if text should still be readable). The good thing is that we can use a single SDF shader to display all the GUI (only alpha values between 0 and 1 are distorted, edges excluded). So in short we can still use a single shader for all the GUI, if we don't use semi-transparent user textures.

  • Small fonts don't look sharp enough (to fix this, same people use some form of super-sampling in the shader, but this is only necessary for small font sizes, and I've never tested this myself).

P.S. The approach I used was to apply an algorithm (edtaa by Stefan Gustavson) to the whole font texture.
However now stb_truetype.h should support signed distance font creation directly AFAIK: maybe the results can be better.

@OvermindDL1
Copy link

(BTW: they're not a font style, but a different way to display fonts).

Yes true, I meant it as in a a new rendering style, not a font style. ^.^;

They require a specialized shader (they don't work without shader support, even if text should still be readable). The good thing is that we can use a single SDF shader to display all the GUI (only alpha values between 0 and 1 are distorted, edges excluded). So in short we can still use a single shader for all the GUI, if we don't use semi-transparent user textures.

Yes this, but considering that is anything about 20 years old or newer, as well as all mobile devices, fine for me (even if opt-in). :-)

Small fonts don't look sharp enough (to fix this, same people use some form of super-sampling in the shader, but this is only necessary for small font sizes, and I've never tested this myself).

That is much less of an issue if different SDF storage is used to store more data in the different color fields (there are examples online).

However now stb_truetype.h should support signed distance font creation directly

Wait really? I've been making them by hand... o.O
Oooo....

@Flix01
Copy link

Flix01 commented Oct 30, 2017

Yes this, but considering that is anything about 20 years old or newer, as well as all mobile devices, fine for me (even if opt-in). :-)

I agree: probably there are more GPUs that don't work without shaders than GPUs that don't support shaders at all around (but I'm not totally sure of it).
However the fragment shader that is needed to display SDF requires the GL_OES_standard_derivatives extension on GL_ES; if it's an extension maybe some old devices don't have it...

That is much less of an issue if different SDF storage is used to store more data in the different color fields (there are examples online).

I didn't know it. I made some experiments using https://github.com/Chlumsky/msdfgen in the past, but I didn't know it could improve the quality of small fonts. I thought its purpose was to avoid the "roundness" of SDF font upscaling.
Also I was not too much convinced by the improvements over plain SDF.

Wait really? I've been making them by hand...

Really? stb_truetype.h introduced SDF support on 2017-07-12.

@OvermindDL1
Copy link

Really? stb_truetype.h introduced SDF support on 2017-07-12.

Oh that's awesome, I last updated my copy over a year ago... ^.^;

@richardlalancetteyoui
Copy link

richardlalancetteyoui commented Nov 14, 2019

Adding support for SDF style fonts would allow for pretty arbitrary scaling without blurriness or expensive memory cost if a good SDF style font is used.

Not cross platform and can be slow.

@OvermindDL1
Copy link

Not cross platform and can be slow.

Uh, what do you mean not multiplatform? A signed distance field font is just a method of rendering a font to a bitmap to encode angle information to allow arbitrary scaling, it's not a format or anything, and the only slow part is the preprocessing, which normal font rendering has as well, and after that it's just as fast as rendering normal fonts...

@richardlalancetteyoui
Copy link

Can't use SDF on all platforms. We have issues on some platforms that we need to fallback to bitmap font.
Some platforms do not have shaders to render them and some shaders do not have derivatives operation or are too slow.

@OvermindDL1
Copy link

OvermindDL1 commented Nov 14, 2019

Some platforms do not have shaders to render them and some shaders do not have derivatives operation or are too slow.

Such as? I'm honestly quite curious. The shaders that SDF needs are supported since early OGL2's time period, mid-late 1990's, in addition to software renderers. At it's most basic with no effects it's a simple strength test.

At it's most basic you could even do that preprocess pass manually from an SDF texture to a normal non-SDF texture for a variety of resolutions as is needed for the tasks at hand.

@richardlalancetteyoui
Copy link

richardlalancetteyoui commented Nov 15, 2019 via email

@OvermindDL1
Copy link

OvermindDL1 commented Nov 15, 2019

Not seeing anything about the supported GL version, but everything there seems well post OGL2's or EGL1's time period. Or if really wanted then preprocess the SDF (or the font itself a bit slower). ^.^

@camplowell
Copy link

camplowell commented May 16, 2021

However the fragment shader that is needed to display SDF requires the GL_OES_standard_derivatives extension on GL_ES; if it's an extension maybe some old devices don't have it...

I recently ran up against this issue when coding an implementation in WebGL, but I found that you can get the slope for uniformly scaled fonts just using the font size and UV-space* slope (calculated by pixel width and atlas resolution).

You can check my work at https://github.com/camplowell/SeaOfNet/blob/main/src/MSDFRenderer.ts
I may have gotten some of the generalizations wrong, since I only tested on one font, but the idea is there. As a side note, I'm using MSDF fonts in this, which uses the median of 3 SDFs (recorded as RGB) to achieve perfectly sharp corners.

*edit: better wording

@Flix01
Copy link

Flix01 commented May 16, 2021

@camplowell: Thanks.

P.S. This pull request is probably the most advanced Dear ImGui SDF font integration available at the present time: #4056 (it uses stb_truetype.h directly).

@GuoZiyangTYUST
Copy link

GuoZiyangTYUST commented Mar 16, 2022

how to switch font when I add same font twice with difference font size?

sorry, i found it. ImGui::PushFont()/PopFont()

@xland
Copy link

xland commented May 17, 2022

how about this issue's progess

@cmaughan
Copy link
Contributor

FWIW, I've been playing with a somewhat related solution to this problem.
I did it by compiling in the FontStash code, then adding a function to upload textures when the font stash changes (as NanoVG does it). Then I use ImGui to render the resulting quads using IDrawList->PrimQuadUV.
Effectively giving an alternative font rendering option which works at scale, without having to hack the ImGui code. The only difficulty here is providing a function in your backend to create/upload textures for the dynamic font atlas (In my case I'm using Vulkan).
This is a work in progress, and not particularly optimal yet, but it solves the problem for me.
There is a video of it working here:

https://www.youtube.com/watch?v=I0QKoqgYrPQ

image

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