Make FreeType select a size for fixed sized fonts
This PR implements:
- select size for fixed sized unscalable bitmap fonts (sbix and CBDT/CBLC)
- rescale bitmap before adding it to atlas
This enables imgui+freetype to just use the system provided emojie fonts. (NotoColorEmoji and AppleColorEmoji)
TODO:
- [x] Better rescaling using box sampling
- [ ] More testing
- [ ] niche api usages
- [ ] more fonts
- [x] multi bitmap fonts without fallbacks (apple emoji)
- [x] em square pr (hm looks the same, but that pr has uncommited changes)
- [ ] figure out why emojies are generally offset upwards
This should make CBDT fonts like NotoColorEmoji and AppleColorEmoji play nice. Bitmap fonts are often preferred by distributors over COLRv1, because they are more universally supported, while also being smaller than SVGinOT fonts.
see https://github.com/ocornut/imgui/issues/6302
built-in font + system provided NotoColorEmoji (109px) at font size 13:
built-in font + system provided NotoColorEmoji (109px) at font size 26:
Old images
built-in font + system provided NotoColorEmoji (109px) at font size 13:
built-in font + system provided NotoColorEmoji (109px) at font size 26:
Old Old images
built-in font + system provided NotoColorEmoji (109px) at font size 13:
built-in font + system provided NotoColorEmoji (109px) at font size 26:
I know this is unfinished but please make sure you follow the local coding style (brace placement, c-style cast, uppercase first letter in comment, etc.) as this really facilitate me looking at PRs. Thank you.
I know this is unfinished but please make sure you follow the local coding style (brace placement, c-style cast, uppercase first letter in comment, etc.) as this really facilitate me looking at PRs. Thank you.
Ofc, I will do that. I am used to telling others the same thing. :)
c-style cast
So I should use (float)var instead of float(var) ?
So I should use (float)var instead of float(var) ?
Yes! Thank you!
I have now also added downscaling using Point Sampling / Nearest Neighbor. Formatting is probably correct too.
Any TODOs left in the code now need to be resolved, before this pr is ready. Feel free to address them.
The biggest TODO is https://en.wikipedia.org/wiki/Image_scaling#Box_sampling . I wanted to have NN first, so I can compare and get the sizing/placement of the texture correct first, which it now hopefully is.
The placement sometimes seems odd, especially mixing fonts, but I guess that relates to #8857 , which I have not yet reviewed/tested this code with. There will probably be light conflicts.
edit: I also updated the images in the OP.
Ceiling bitmap size, instead of Flooring it.
| size | floor | ceil |
|---|---|---|
| 13 | ||
| 26 |
More in line with the rest of the code. Also feels placed more correctly. NN scaling looking decimating in all scenarios, naturally.
Downscaling should use bilinear filtering, should be done using its own dedicated function. It doesn't need to be fancy/optimized.
Downscaling should use bilinear filtering, should be done using its own dedicated function. It doesn't need to be fancy/optimized.
No, bilinear looks bad when downscaling. (see https://stackoverflow.com/a/49883346 ) Yes I will move the scaling to it's own function.
Point sampling / Nearest Neighbor (26):
Box sampling (26):
Point sampling / Nearest Neighbor (13):
Box sampling (13):
The difference between Point sampling and Box sampling looks more stronger with bitmaps that have more details (higher frequencies) like the AppleColorEmoji font:
26 Point sampling
26 Box sampling
13 Point sampling
13 Box sampling
Notice the 8-ball becoming a 9-ball with nn, the basketball looking all bad etc.
I got hold of the original apple color emoji tcc (from macOS 15.4), which has multiple bitmap resolutions:
pixelsize: 20 26 32 40 48 52 64 96 160
Not only does my code not select the correct one (it selects the next smaller one, instead of the next bigger one), it also showed that my code misbehaves when it should be upscaled from a smaller bitmap (should then be done by the gpu sampler instead).
edit: Also to note is that the apple font is using sbix instead of CBDT/CBLC.
=============================> TTC font 0
version=1, numtables=21, searchRange=256 entrySel=4 rangeshift=80
File Checksum =825d2af (should be 0xb1b0afba), diff=a98add0b
DSIG checksum=00000001 actual=00000001 diff=0 offset=225424 len=8
GDEF checksum=383a384b actual=383a384b diff=0 offset=225648 len=694
GPOS checksum=5086b592 actual=5086b592 diff=0 offset=226344 len=726
OS/2 checksum=60ae7715 actual=60ae7715 diff=0 offset=225552 len=96
bgcl checksum=1dc60d7c actual=1dc60d7c diff=0 offset=299772 len=69405
cmap checksum=035aa5c7 actual=035aa5c7 diff=0 offset=227072 len=3568
feat checksum=07d60663 actual=07d60663 diff=0 offset=225500 len=52
glyf checksum=3bcbaa6d actual=3bcbaa6d diff=0 offset=369180 len=111812
head checksum=fb5ccc6f actual=fb5ccc6f diff=0 offset=872 len=54
hhea checksum=03220268 actual=03220268 diff=0 offset=744 len=36
hmtx checksum=710f11f4 actual=710f11f4 diff=0 offset=245472 len=7562
loca checksum=6e2dd798 actual=6e2dd798 diff=0 offset=230640 len=7412
maxp checksum=0f0202ce actual=0f0202ce diff=0 offset=225432 len=32
meta checksum=0f0dbab0 actual=0f0dbab0 diff=0 offset=4036 len=1896
morx checksum=dceb2acb actual=dceb2acb diff=0 offset=480992 len=423468
name checksum=f98d1530 actual=f98d1530 diff=0 offset=1484 len=708
post checksum=27ba27f8 actual=27ba27f8 diff=0 offset=253036 len=46734
sbix checksum=bde80893 actual=bde80893 diff=0 offset=904460 len=187685208
trak checksum=019d00a9 actual=019d00a9 diff=0 offset=928 len=60
vhea checksum=01f71130 actual=01f71130 diff=0 offset=225464 len=36
vmtx checksum=0640005a actual=0640005a diff=0 offset=238052 len=7418
(should then be done by the gpu sampler instead)
~This might not scale well past 2x upscaling, as then the bilinear sample taps might touch neighboring textures (assuming 1px boundary)~ nvm, the boundary pixel should be fine
I am contemplating using the downscale function to also just upscale them before adding them to the atlas.
Making use of the current size selection bug, selecting the next smaller size:
upscaled using Point sampling
upscaled using Box sampling
Box sampling might be good enough.
With the size selection fixed, it is now downscaling and looking good.
I decided to always rescale now, if the size is not an exact match.
The last issue (besides more testing) that I know of is the consistent vertical offset:
This seems to be different per font, but is more noticeable with apple emoji.
edit: Noto seems to also have a horizontal offset:
I've been looking for this!