ppy / osu-framework

A game framework written with osu! in mind.
MIT License
1.66k stars 419 forks source link

CSS-compatible font sizing #3271

Open bdach opened 4 years ago

bdach commented 4 years ago

Recently osu!-side there have been multiple contributions that aimed to bring visuals as close to web as possible. An issue raised during that period was that the numerically-identical font size looked smaller in the game than in web.

Right now, SpriteText & co. work in a way such that a height of 16 will yield a text sprite of the size of precisely 16. While that's what seems reasonable, it's actually not what CSS does:

image

At this point I'll quickly defer to this article explaining how CSS font-size works. Especially relevant is this picture:

which shows that for a font:

the effective text height in pixels of a 100px line is actually 164px.

To see how this relates to how framework handles text, I used the existing SpriteText test scene, Open Sans and FontForge. The metrics for Open Sans are:

That means that:

The measurements in-game seem to indicate that currently the framework is sizing the entire line (ascender to descender) when size is supplied, instead of sizing the em-square:

font-sizing

126 * 52.4% comes down to just over 66 pixels. Measurement is imprecise due to antialiasing. I've only checked this one font, but seems too much of a coincidence if that turned out to be a fluke.

Font size supplied in game was 92, but measured 126 due to an ancestor DrawSizePreservingFillContainer. After adjustment the entire SpriteText should have 126 / 73.4% = ~171 height.

Now, the bad news is, as far as I can see font spacing info comes opaquely through bmfont, and all the dimensions above are font-specific, therefore we'd most likely have to modify bmfont to supply us this info, as it doesn't seem to be there. There is a base attribute in the common tag, but seems to be the ascender-to-baseline measurement, so not what we want here.

It's also not entirely clear what should be done with the ascender and descender sizings. They should be taken into account somehow. The "easiest" way I can see out of this is to make bmfont spit out the numbers needed to make the necessary adjustment (namely, the em-square and ascender + descender heights) and apply sizing adjustment game-side.

I'm aware of the scope and amount of work this could take, and for how little gain it would be. It would probably be nice to have this corrected (as this is probably the more correct, and expected in the eye of consumers, behaviour), but there's way more other important issues to deal with, therefore opening as proposal.

(Also painfully aware this could end up being a big breaking change.)

bdach commented 4 years ago

I began to doubt all of the above, but I figured out a way to capture a better screenshot that seems to confirm my reasoning:

image

Note the following:

peppy commented 4 years ago

If it's always a constant ratio, we can fix this by applying a scaleAdjust to the font/texture store. This can be done on a per project basis, or at the framework level if we decide that is more correct.

frenzibyte commented 3 years ago

It is different between each font, e.g. for the "torus" font:

so the ratio to apply with scaleAdjust will be 100f / 1.2f (100f default scale adjust divided by effective text height / em square), different from "Open Sans" which will have a scaleAdjust of 100f / 1.36f instead.

but that means it can still be done by separating each font family to its font store and calculate the required scale adjustment for them, in an organized way, and potentially move it to a method here in framework.

Though after doing so, all the sprite texts in osu!lazer may need to be revisited as currently the scale adjustment makes things look very off, but is to be expected:

CleanShot 2021-05-16 at 11 59 10