Nuklear icon indicating copy to clipboard operation
Nuklear copied to clipboard

Sample for how to use non-baking font drawing?

Open ronaaron opened this issue 5 years ago • 15 comments

The font-baker is very convenient, but it has limitations: among them, "too many" fonts or "too big" doesn't work as-is.

The documentation indicates it should be pretty easy to do custom font handling, but there aren't any samples showing a for-instance, as far as I can see.

Does anyone have such a sample? I would still like to use the stb_truetype functionality, but make it something 'on demand' instead of frozen at startup.

ronaaron avatar Apr 28 '20 03:04 ronaaron

OK, I see the 'x11' sample actually has a simple version solely for X11. If anyone has a version using stb_truetype, I'm very interested

ronaaron avatar Apr 28 '20 04:04 ronaaron

The attached file is a modified version of the demo/sdl_openg3/main.c which demonstrates the problem. Compile it, and then give a font size and font file name on the command line.

So, e.g. demo 16 simfang.ttf works, while demo 18 simfang.ttf doesn't (on my machine, YMMV depending on memory etc).

Related to my pull request #54 , but that fix only makes this problem appear at a bigger font size.

main.zip

ronaaron avatar Apr 28 '20 15:04 ronaaron

I'm working on trying to implement a "bake-on-demand" method using the stb stuff. I'm having a bit of trouble figuring out just how one decides how big a bitmap (WxH) to make for a given character. The method used in nuklear seems to be arbitrary to me.

I mean, if a font is supposed to be rendered at 16 pixels, why should the bake bitmap be 512 px?

Anyone have insights to share?

ronaaron avatar Apr 29 '20 18:04 ronaaron

Just for reference, @ronaaron submitted https://github.com/Immediate-Mode-UI/Nuklear/pull/54 which seems to be stuck exactly on this "baking process".

There seems to be some reference to baking on line https://github.com/nothings/stb/blob/master/stb_truetype.h#L102 . Feel free to investigate.

dumblob avatar Apr 29 '20 19:04 dumblob

Um... yes, I know I submitted #54... I even mentioned that in the third post here.

OK, I was hoping some one of the maintainers of Nuklear knew how the font stuff fits together.

ronaaron avatar Apr 30 '20 04:04 ronaaron

I even mentioned that in the third post here.

Sorry, didn't notice in all those emails (or might have been an edit and thus I didn't get it per email :wink:).

OK, I was hoping some one of the maintainers of Nuklear knew how the font stuff fits together.

IIRC this buffer sizing was a pure "educated guess" back then and it remained so until today. But I'd start with the line in stb_truetype.h I linked above.

dumblob avatar Apr 30 '20 08:04 dumblob

I have been able to 'demand-load' font pages (e.g. unicode pages) using stb_truetype, and write out the image data. That part works fine.

What I'm having trouble with is that the way Nuklear uses fonts is that it assumes that the bitmap is already loaded in a texture before it starts issuing the draw commands. That is, it first loads the texture, then it issues a bunch of sub-image commands. That of course does make sense.

But in the 'demand load' scenario I'm trying to make work, the 'bitmap' doesn't exist until someone queries the font information.

Also: the nk_user_font callbacks get the 'userdata' of the font, but not the font itself. It would be more useful to have the font, since I need to reallocate the bitmap. Currently, I just store the font ptr in the userdata, but that's a waste.

ronaaron avatar May 03 '20 06:05 ronaaron

@ronaaron now I start to understand why you feel the "dynamic font loading" is a bit cumbersome.

Feel free to make a PR (doesn't need to be anything final - just a proposal of potential way how to ease the dynamic font loading) and we'll discuss it more technically there.

But in the 'demand load' scenario I'm trying to make work, the 'bitmap' doesn't exist until someone queries the font information.

Didn't look at the code, but isn't this just an assert bitmap != null; -> if( bitmap != null ) return; change somewhere?

dumblob avatar May 03 '20 06:05 dumblob

I don't have this code checked in to where a PR is possible. Why not just create a tracking issue to work out the issues?

ronaaron avatar May 03 '20 07:05 ronaaron

I don't have this code checked in to where a PR is possible.

Ah, ok. I supposed you do :wink:. Sure, let's discuss it further.

dumblob avatar May 03 '20 13:05 dumblob

My fork has a fix to support what I'm currently doing in 8th, which is "demand-loading" of fonts by unicode-pages. The problem in current Nuklear is that when drawing text, it assumes the handle is always the same. That's not the case in my code, where if a font supports (say) English and Russian characters, the code-pages for those fonts are loaded in separate bitmaps (for the same font).

I no longer use the "baking" built-in to Nuklear, because it is very wasteful of memory (e.g. especially WRT Chinese fonts). I can now load many more fonts simultaneously, and at larger sizes. And it's faster to load "on demand", as well.

The way it works is that when a codepoint is requested to be measured, my code checks the font (my font structure) to see if the code-page is loaded; if not, it loads it and updates the handle. The last accessed code-page for the font is held in a 'cache', so that in the normal case of a run of characters from the same code-page, the access is fast.

Feel free to take my changes to Nuklear's drawing code to support this.

ronaaron avatar Aug 09 '21 05:08 ronaaron

My fork has a fix to support what I'm currently doing in 8th, which is "demand-loading" of fonts by unicode-pages. The problem in current Nuklear is that when drawing text, it assumes the handle is always the same. That's not the case in my code, where if a font supports (say) English and Russian characters, the code-pages for those fonts are loaded in separate bitmaps (for the same font).

I no longer use the "baking" built-in to Nuklear, because it is very wasteful of memory (e.g. especially WRT Chinese fonts). I can now load many more fonts simultaneously, and at larger sizes. And it's faster to load "on demand", as well.

The way it works is that when a codepoint is requested to be measured, my code checks the font (my font structure) to see if the code-page is loaded; if not, it loads it and updates the handle. The last accessed code-page for the font is held in a 'cache', so that in the normal case of a run of characters from the same code-page, the access is fast.

Feel free to take my changes to Nuklear's drawing code to support this.

Is this stable? Like is it scalable to any font size and any font language such as Chinese, English, Arabic, and so on

Also does this modify existing api or does this introduce new APIs specifically for this?

Could you provide an example? :)

mgood7123 avatar Sep 17 '21 10:09 mgood7123

It is stable AFAICT, and it was specifically tested on large Chinese fonts (e..g at large size, like 70px). The language doesn't make a difference, since the glyph is looked up by unicode code-page, it's all the same as far as the code's concerned.

It doesn't modify the Nuklear API, but it does change how the drawing code works because as I mentioned, the code page may be different and thus a different bitmap needs to be used (the Nuk. code assumes the same bitmap for all drawing of a font; I suppose that would have been possible by resizing the bitmap, but my way is much easier to implement).

Unfortunately, my implementation of the font-loading (in my 8th kernel) has a lot of 8th-specific code which would only make things less clear...

ronaaron avatar Sep 17 '21 10:09 ronaaron

It is stable AFAICT, and it was specifically tested on large Chinese fonts (e..g at large size, like 70px). The language doesn't make a difference, since the glyph is looked up by unicode code-page, it's all the same as far as the code's concerned.

It doesn't modify the Nuklear API, but it does change how the drawing code works because as I mentioned, the code page may be different and thus a different bitmap needs to be used (the Nuk. code assumes the same bitmap for all drawing of a font; I suppose that would have been possible by resizing the bitmap, but my way is much easier to implement).

Unfortunately, my implementation of the font-loading (in my 8th kernel) has a lot of 8th-specific code which would only make things less clear...

Hmm ok :)

And cool

Also how does it perform for very large font sizes? Eg 256 px/pt and greater

As I find it better to load at 256 and downscale

Specifically load the font and then upscale it to a factor of 2 before loading the next size

I find that any more than 2x upscale reduces quality

For example

Load font at 128 and downscale/upscale from 1 to 255 Load font at 256 and upscale from 256 to 511 Load font at 512 and upscale from 512 to 1027 Load font at 1024 and upscale to infinity (not much point loading any greater than 1024)

Exact range can be specified via array and depends on font loading speed

mgood7123 avatar Sep 17 '21 13:09 mgood7123

Haven't tried 256px fonts, but if there's enough memory on the video card, it should work fine. My experience has been that rendering at the specific desired px size is better than resizing, but I also don't typically use huge font sizes...

ronaaron avatar Sep 18 '21 17:09 ronaaron