Skip to content

Conversation

@Green-Sky
Copy link
Contributor

@Green-Sky Green-Sky commented Oct 17, 2025

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:

  • Better rescaling using box sampling
  • More testing
    • niche api usages
    • more fonts
    • multi bitmap fonts without fallbacks (apple emoji)
    • 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 #6302


built-in font + system provided NotoColorEmoji (109px) at font size 13:

image

built-in font + system provided NotoColorEmoji (109px) at font size 26:

image
Old images

built-in font + system provided NotoColorEmoji (109px) at font size 13:

image

built-in font + system provided NotoColorEmoji (109px) at font size 26:

image
Old Old images

built-in font + system provided NotoColorEmoji (109px) at font size 13:

image

built-in font + system provided NotoColorEmoji (109px) at font size 26:

image

@Green-Sky Green-Sky force-pushed the fixed_sized_bitmaps_density1 branch 2 times, most recently from 8f1ace7 to 3ec8f95 Compare October 21, 2025 20:51
@ocornut ocornut changed the title Make freetype select a size for fixed sized fonts Make FreeType select a size for fixed sized fonts Oct 22, 2025
@ocornut
Copy link
Owner

ocornut commented Oct 22, 2025

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.

@Green-Sky
Copy link
Contributor Author

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) ?

@ocornut
Copy link
Owner

ocornut commented Oct 22, 2025

So I should use (float)var instead of float(var) ?

Yes! Thank you!

@Green-Sky Green-Sky force-pushed the fixed_sized_bitmaps_density1 branch from 3ec8f95 to 8ba0592 Compare October 22, 2025 14:35
and scale it down before adding it to atlas to save on atlas space.
@Green-Sky Green-Sky force-pushed the fixed_sized_bitmaps_density1 branch from 8ba0592 to f8e941e Compare October 22, 2025 19:53
@Green-Sky
Copy link
Contributor Author

Green-Sky commented Oct 22, 2025

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.

Looks more correct and more in line with other parts of the code.
@Green-Sky
Copy link
Contributor Author

Green-Sky commented Oct 24, 2025

Ceiling bitmap size, instead of Flooring it.

size floor ceil
13 image image
26 image image

More in line with the rest of the code. Also feels placed more correctly. NN scaling looking decimating in all scenarios, naturally.

@ocornut
Copy link
Owner

ocornut commented Oct 24, 2025

Downscaling should use bilinear filtering, should be done using its own dedicated function. It doesn't need to be fancy/optimized.

@Green-Sky
Copy link
Contributor Author

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.

@Green-Sky
Copy link
Contributor Author

Point sampling / Nearest Neighbor (26):

image

Box sampling (26):

image

Point sampling / Nearest Neighbor (13):

image

Box sampling (13):

image

@Green-Sky
Copy link
Contributor Author

Green-Sky commented Oct 25, 2025

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

image

26 Box sampling

image

13 Point sampling

image

13 Box sampling

image

Notice the 8-ball becoming a 9-ball with nn, the basketball looking all bad etc.

@Green-Sky
Copy link
Contributor Author

Green-Sky commented Oct 25, 2025

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).

image

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

@Green-Sky
Copy link
Contributor Author

Green-Sky commented Oct 25, 2025

(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

@Green-Sky
Copy link
Contributor Author

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

image

upscaled using Box sampling

image

Box sampling might be good enough.

@Green-Sky
Copy link
Contributor Author

With the size selection fixed, it is now downscaling and looking good.

image

I decided to always rescale now, if the size is not an exact match.

@Green-Sky
Copy link
Contributor Author

Green-Sky commented Oct 27, 2025

The last issue (besides more testing) that I know of is the consistent vertical offset:

image

This seems to be different per font, but is more noticeable with apple emoji.

edit: Noto seems to also have a horizontal offset:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants