-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
How to load txt-based .fnt and .ttf files #102
Comments
Thanks, I will look at it. I may want to take the stb_truetype/TTF code and rework it to integrate in the main code. Converting to a common format optimal for runtime makes sense (this common format may or not be the current bitmap font format, let's start with that since this is what we have now but it could possibly change), eventually the font loader could just convert whatever input in the format ImGui uses internally, like you did. I had noticed that something about the font baseline/display offset isn't handled properly in the current code. Need to have a look at it. |
Looking at it now. I'll be using the new stb_rect_pack.h API and subsamping. What is the purpose of bool allowNonSquaredBitmap=false in your code? Is it ever an advantage or requirement to have square textures? |
Testing Arial Unicode rendered with stb_truetype.h (without kerning / subpixel rendering yet) proggy_clean.ttf also works well now. Identical output as the bitmap one. I'd be tempted to drop the bitmap version but the .ttf size would affect the size of imgui.cpp very noticeably. Might look into finding if embedding a small compressor would be a good middle ground. Still lots of work to do. Fixing alignment / scaling issues. Testing with different renderers. Using the better packing. Handling errors and corner cases (there's various bugs in your version nothing major). Cleaning up. Adding the API or finding the best way for the user to specify character ranges (or make it automatic). Consider real world scenario or using different fonts and varying scale (possibly provide cache/helper for sizes). Figuring out how this may or not affect the initialisation step and the setup (avoid breakage, but there will be "some", e.g. the UV previously used with bitmap font required disabling bilinear filtering, so users will need to re-enable that in their codebase, etc.). The important side-effect improvement is that if ImGui has control over the texture before it is passed into GPU then I can easily poke things manually. Also I can derive of using structures that are binary matches for AngelFont and uses something that more optimal for runtime (even if it means converted angel fonts during init). Lots of improvements ahead but I will probably have to shelve my work and resume later. |
The output bitmap width and height can be bigger than the input width and height: if that happens allowNonSquaredBitmap can be used to double the bitmap width only and doing an additional try before doubling the bitmap height too (note that the name is a bit misleading: it just deals with doubling the input parameters in a separate way). That may result in smaller textures (= less memory).
Then we can say goodbye to outline font support...
Yes, but usually we can retrieve the bitmap data for .fnt files too (for example by using stb_image to manually load the texture, before feeding it to opengl/direct3d, or by finding a way to download pixel data from the graphic card): this way we can handle the texture ourselves when using .fnt files too. P.S. As I've written, I did not need true type font support, because I can easily embed .fnt files in .txt format for portability (and this way I can use outline fonts too). That's why I hope you won't drop .fnt files... P.S.2. One advanced topic for making the font look good at different scaling values would be to add a manual mipmap generator. Libraries like fontstash solve this problem continuously adding glyphs at different sizes to a set of textures: that's the best possible solution if we can waste texture space (although I don't like this approach). Automatic generation of mipmaps on font texture often produces artifacts/texture bleeding. Manually generating mipmaps by scaling each glyphs separately seems to be a possible way to avoid these artifacts. Here is a link about a similiar approach: http://www.google.it/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAA&url=http%3A%2F%2F0fps.net%2F2013%2F07%2F09%2Ftexture-atlases-wrapping-and-mip-mapping%2F&ei=qAOtVJXAGoHdasfVgcgH&usg=AFQjCNFk12Jnl3yBAvYQ9YDGNnGEZkoBzg&bvm=bv.83134100,d.d2s |
Re. allowNonSquaredBitmap - so my question stands, what is the point in enforcing square texture when one can save space with non-square textures ? We could also use distance-field textures for scalable fonts (thought it my experience they aren't that good with very small sizes). Either way I think it is a bit over-reaching to allow freely scalable font and try to optimally solve every case. ImGui is still meant to be for building debug tools and doesn't need to be QT or HTML. It should be fairly easy for the users to generate a few sizes if they need them. How are you using outline fonts, do you have a screen-shot ? I'm just curious, it feels a bit old-school (and that's coming from me, I usually like old-school). |
Sorry. I thought some openGL implementations might not support non-squared textures: but I have to check if this is true...
Yes, that's the number-one option, but it's probably too much for imgui... my proposal was intended only as an advanced option, if we allow a single size font.
Fully agreed.
DejaVu Serif Condensed Outline:
The best way for the user would be to simply pass a UTF8 character string. I don't know the imgui internals, so I don't know if there are methods for extracting utf8 codepoints from a string (a char*): to do so I use is the piece of code that fontstash library includes: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ I like it. Bjoern Hoehrmann's code is very concise and it just works. Obviously I did not include it in my gist to keep the code short enough. Also note that some old compilers might not accept UTF8 encoded source files and thus it should be better to just add some method to convert a utf8 string to a vector of codepoints, and a loadFromTTF(...) overload that calls the existent code. |
Passing a string wouldn't work, I'm talking about huge range here for CJK (I think the recommended range for Chinese has 21 thousands characters). I'm adding function like that in ImFont my work version
Probably a separate function for just Japanese/Korean. Thanks for the link, interesting stuff (I wanted to optimize the UTF-8 decoding possibly). |
Oh, that's OK then. |
A 2048x2048 texture works well, you can fit e.g. a baked 15x15 full character set. |
I am committing to a branch Would be nice if someone tested the TTF branch in their real app and posted feedback on it.
I an unhappy about the breakages and still figuring out if / how I can alleviate them. Additionally some of those setup api may change before I merge back in. Also .bmf font loading was dropped, it was just much more simple this way. It is possible to resurrect it by converting the .bmf data to the new runtime structure and ensuing that extra space is added to the texture. I don't think it is worth it but it is possible. Refer to branch commits |
Will also merge in Which will add a reference back to the texture in the ImDrawCmd (the identifier probably in the form of a user-set void*). Allowing for multiple fonts to be used along with images. Need to consider the side-effect of using a 1 channel texture for the font. If the user wants to mix font and images (unlikely to be 1 channel) then their texture identifier has to become more of a "material / shader" identifier which be more annoying to setup on some codebase? A way to simplify would be to turn the font texture into RGBA at slight GPU bandwidth cost (probably minor), will probably do that. Or even a way to request the texture pixels data from ImGui and it can come in both Alpha-only or RGBA formats. For multiple fonts later on should provide helpers to pack them into a single texture. |
Also note that the stb_truetype.h embedded in the new branch is a modification of the original. The main modification allows to determinate the size of the atlas without performing any rendering, to avoid incrementally trying/failing/resizing (unacceptable for big fonts). |
Have you thought about adding glyphs dynamically to the atlas as you go? I do that in fontstash [1], and it simplifies multi font case a lot. |
Might do but also trying to keep it simple so I'll skip on that right now. I still expect people to use ASCII-extended set for ImGui so dynamic atlas would mainly make sense for dynamic font resizing. I'm very content right now with what the change brings (TTF, imgui's own texture space, image display soon) so there's a fair bit to work on from there. |
I am pretty much done with this branch and improved things a fair bit since the last post. The only breakage is that: Became I am keeping the breakage because earlier had different parameters and returned PNG data whereas new API returns uncompressed pixels. Might add a dummy GetDefaultFontData() that asserts and inform programmer with the fix. Also added a new field in ImDrawCmd for additional textures but user only needs to handle it if they use images or multiple fonts (which are both new features) so it won't be perceived as breakage. New API ImGui::Image() to display textures. Will add the other API from #73. Here's how it looks with Arial Unicode, size 20, no oversampling. |
Regarding outline fonts, I have a separate fork of stb_truetype at work that generates outlines (or rather just dilates characters so that it looks like an outline when the regular character is drawn on top of it), and I'll be integrating that back into the public stb_truetype at some point. |
Hope that will be integrated into ImGui: that will help me regaining happiness after the announced drop of .bmf files... P.S. I might be wrong, but I think that the outline of .bmf fonts is not made by simply pasting a smaller glyph on the top of a bigger one: maybe there's some way of scaling the bezier curves directly (outward for the outer contours and inward for the inner ones, or viceversa depending on the approach we take...). However I'm not too sure about it. In any case thank you for the branch! |
Yes, "dilating" means expanding it in all directions, rather than just using a larger version of the character (in which case you wouldn't get outlines on the holes and such). Doing it with the beziers might be conceptually simpler, but there's problems when they self-overlap, so it's easier to just use a bitmap operation (in this case, it's essentially a gaussian blur and then a threshhold operation). |
Thank you for your explanation! That means that the outline will look good! |
Merged the TTF branch into trunk. I spent a considerable amount of time getting this right
The basic use case is:
But you can do:
Both fonts built into same atlas, merging draw calls (so most windows will still be 2 draw calls at the moment). ** ImGui styling is still rather awkward, lots styling parameters are specified in pixels and thus may not scale the way you expect if you rescale a font. The library is still intended to minimize screen real estate use but better styling would be helpful. Styling is also awkward because of the semantic of some colors items can sometimes be unclear. That will be a future thing to work on. I'd appreciate feedback on transitioning to this version. If there's any way I can improve the various bits of documentation, etc. |
@ocornut I'm currently making some early experiments on it. At my current state of the code I don't think .fnt support is worthy of being readded (but if you need it, I can try refining the code and post a .diff file somewhere...). P.S. I'm not using any embedded image loader, the new AddFont method takes a pointer to the font bitmap (users can use any image library they like). P.S.2.This is about Signed Distance Fonts. I've just found a free tool that can export a .fnt file of a signed-distance-bitmap-font here: http://www.gamedev.net/topic/491938-signed-distance-bitmap-font-tool/ (the .fnt format exported by this tool is outdated and misses some data; but it's very easy to fix, as its code is very compact, portable and easy to tweak to be compatible with the txt .fnt format I can load into ImGui). |
I have so much higher priorities on ImGui now that I'll just let this slide until stb_truetype eventually support outlining. It'll be more sane and simple. |
As I've written in the last post I'm not sure that ImGui allows retrieving the rendering lists on a per-font basis (SDF fonts require a specialized shader). Unless you mean having a specialized texture for SDF fonts (it's an alpha texture that can be merged to the main ImGui texture).
That's nice, as long as the creation process will be fast enough (there might be thousands of glyphs to process). Beside that, readding .fnt support wouldn't have broken anything existent. But of course that's up to you. So I accept your decision. |
Yes SDF won't be on by default, hypothetically user would enable it and then the atlas would allow you to retrieve a SDF texture and then it is up to the user to render it. |
In the weekend I made this imgui "extension", mainly to allow imgui users to load .fnt files in "text" format (actually it should autodetect if the .fnt is "text" or "binary" during the loading phase).
Using the "text" .fnt format can be a useful way to improve code portability by solving endianess related problems (please see #81).
As an extra I've added an optional preprocessor definition that can be used, together with stb_truetype.h, to load .ttf files (it's experimental, it was not my main concern, but I found out that I could reuse a lot of the code I had just written and then I made it).
Here is the gist with code (with usage instructions in the header file): https://gist.github.com/Flix01/13374fabd73214f82362
The text was updated successfully, but these errors were encountered: