Closed trethaller closed 4 years ago
I've managed to get some progress on that front. Not usable yet, but major parts of the tool are operational.
Primary target is HL, but because I use ammel, it should also work with HXCPP and Eval (when it's fixed in ammel). It's partially done in C, but right now 14pt font generates in a matter of around 1 second with lots of debug print from haxe side. Dependencies:
What a surprise that I actually went and started doing it.
Haha I'm almost feel bad for "just letting you know". Awesome stuff though 👍
Okay, status update. MVP version of the tool is ready and can be found here: https://github.com/Yanrishatum/fontgen
Currently, when rasterizing test config, it takes less than 2 seconds to process 4 fonts at size 24 with different sdf method each, using charset slightly bigger than basic latin.
Tools uses ammer
, hence allows for HL, HXCPP and interp (depending on state of ammer). Currently I only used HL bytecode, but I suppose HLC would work as well.
As long as msdfgen can do that - that tool can too. But there is a need to fix makefiles in order to compile it for linux/mac.
I pack glyphs first, only then render onto texture based on packing results. I use MaxRect algorithm with BestShortSideFit heuristic, and pack into bin with maximum size of 4k, then crop the size based on xMax/yMax before starting rasterization.
inputs
It is possible to specify multiple fonts per config.
Reason: fallback fonts. Since Heaps does not support multi-texture font files, it's preferable to bake all glyphs into one texture, which can pose a problem when dealing with localizations. Obviously, majority of fonts don't carry all possible characters inside, especially for asian languages. Adding fallback fonts it's possible to specify extra fonts for characters that aren't present in the primary font.
Possible improvement: Along manual fallback fonts it's possible to hook into OS on C side and fetch fonts from here. My knowledge of C/OS-level programming isn't that extensive to implement such thing, however.
padding
and spacing
Those are separate and act as follows:
dfSize
. It will be accounted in rendering offset. Defaults to 0
pixels padding.1
pixel spacing.raster
mode is not an "honest" rasterizationI used generateMSDF
-> renderSDF
approach to rasterization of glyphs. Because of that - it is de-facto the slowest rasterization mode. Also see notes below.
Reason: Initally my focus was on SDF rasterizer, and regular pre-render was tacked on in "at least it works" manner. Yes, pretty lame reason. :)
Possible improvements:
freetype
that is already in dependencies..fnt
fileBecause BMF format does not differentiate between SDF and non-SDF font, I decided to add extra line that describes SDF method and parameters. It's added at the end of file, because from what I've seen - some parser really depend on line order being info
, common
, page[]
, chars
, char[]
, kernings
, kerning[]
and would panic if it would find some unaccounted line between any of those.
.fnt
file and integersThis is a pretty big problem for SDF fonts. BMF operates on integers everywhere, while for SDF all ofthe are preferable in either funits or ems to allow accurate scaling and alignment (especially vertical alignment). I would prefer to not modify format further and introduce custom font descriptor for SDF fonts. There are multiple possible implementations:
I will implement support for custom format in Heaps, obviously. It won't affect current font pipeline.
As mentioned previously, it's kinda tacked on, but on top of that it currently uses magic numbers in order to render itself. E.g. offsets glyphs with sort of arbitrary values during MSDF generation. Solutions were mentioned already.
raster
I most likely will add flag that allows to which channel sdf/psdf/raster modes will output (greyscale/alpha).
xadvance
, xoffset
and yoffset
is sketchyWhat the title says. :) Currently it renders "okay-ish", but it's very apparent with yoffset
- letters sometimes don't sit on the baseline. I need to revise the rasterizer parameters (specifically - translate offsets) as well as fnt generator in order to ensure they are rendered at baseline with integer values. Even if we'll use custom SDF descriptor, I still need to do that, because tool will have to support output in both .fnt and custom format. And I don't like magic numbers in the code.
Most likely will add a flag to enforce POT texture. (Or enforce it by default and flag to disable it)
See repo readme, it's very barebones right now, and there isn't even a help print.
Note: I'm not doing support for colored glyphs (unicode emojis for example). Just no.
Looks great!
.fnt file and integers
I understand now why it's not just a matter of replacing some ints by floats. But this seems out of the scope of the current issue (we have used SDF with the current font format and are reasonably happy with it). You're welcome to do these changes, but this wasn't part of the requirements
Sketchy maths / hacks
Not too concerning to me as a product user :-D as long as the results are consistent across fonts and sizes
Output texture is roughly square, but isn't POT
We discussed this with @ncannasse, we don't consider this a problem
Other TODOs
Nice to haves but not blocking
Alpha channel always 1, even on raster
Bitmap (raster) mode: this mode is important for us because we have many bitmap fonts we need to support on our current projects, even if, with this new tools we will probably favor SDF in the future. For me this is the only blocker.
One last thing: a sample ready-to-use config file and windows binary in the heaps/tools
(with the output font in heaps/samples/res
) would be nice (I'm a bit concerned with including a commercial font like Londinia in there, most likely some people will use it without reading the license)
Also I admit we had not really considered the annoyance of reading and interpreting ttf files to generate the glyph coordinates, so Nicolas suggested we add an extra 50€ to the bounty
Quick update: Blocking issues were resolved. I'm getting rid of HxTrueType
library and instead completely rely on Freetype library, as it provides way more accurate hinting. It also being used to rasterize glyphs in raster
mode, resulting in more high-quality output compared to SDF->Raster approach. And since Freetype handles all TTF processing, pretty much all CMap tables should work perfectly fine.
Cleaning up code and doing some finishing touches, so it should be live today or tomorrow.
v1 is essentially ready. It still have room for improvement and optimization, but right now it does what it supposed to do. Going from previous (long) update post:
Positive of hxTrueType
was that it's in Haxe. Negative... It's not fully implemented and performing things like type-hinting would would be pretty hard. Freetype on other hand provides very accurate type-hinting, saving a lot of headache in regard of getting glyphs where they are supposed to be.
Hence hxTrueType
had to go and tool no longer depends on it.
As a consequence, redesigned major parts of native side to work with Freetype more effectively.
raster
mode fixesThis mode now uses Freetype, which yields good results comparable in quality to other tools that rasterize font files.
This version always produces RGBA image, but in future I most likely improve it to save in appropriate format. For sdf
, psdf
and msdf
all pixels are non-transparent, SDF uses other channels to render. For raster
it uses white pixels and glyphs control the transparency.
They are calculated by Freetype, and while testing it looks pretty consistent. (Hail type-hinting)
*
char on FiraCode) I've left it as is for now, but will implement a eventually or if anyone will get this on practice. UPD: Will fix next update.Bytes
when passing data between Haxe and C via Ammer turned out pretty nice.raster
being the fastest working out less than 50ms consistently (all others are 220/350ms+).One last thing: a sample ready-to-use config file and windows binary in the heaps/tools (with the output font in heaps/samples/res) would be nice (I'm a bit concerned with including a commercial font like Londinia in there, most likely some people will use it without reading the license)
I will remove Londinia from repo soon. And I think this part needs separate discussion, as to how it should be integrated. (Ping me up in Discord)
Sample render via Heaps (with 1.1.0, I fixed a few issues, I'll be publishing it tomorrow):
Looks awesome, really happy you ended-up with good results on bitmap fonts as well, switch to freetype was worth it!
Still need to try it but from what I see I'm good to close the issue. Regarding integration into Heaps, I'm now thinking maybe a link to the fontgen repo is enough, or else we could add it as sub-repo under the tools folder actually under heaps/tools we'd most likely only want ready-to-use binaries
v1.1.0 up and running: https://github.com/Yanrishatum/fontgen/releases/tag/1.1.0 The winding fix is opt-in because solution msdfgen uses is pretty slow, adding a good chunk of time to processing. So I would enable it only if there are glyphs that are inverted on SDF methods. Also excluded non-printing character range from rasterization by default, because usually they aren't present in the ttf file, produce missing char warning and shouldn't be rendered in the first place. And also implemented support for 1-bit bitmap output from freetype, enabling pure B&W fonts support in raster mode. zip file should bundle self-contained HL/C exe + .hl file with corresponding hdll/dll (Including libhl).
Great, have been using the windows release without a problem so far, I think we can close this and continue the discussion on the fontgen repo if needed. Thanks!
💰 Bounty - 250€
Note: currently being worked on (see comments)
We would like a command-line tool to automate the creation of Heaps fonts, supporting both Bitmap and SDF font types.
There are two stages in the generation process:
.fnt
file can be createdThe program accepts a configuration file as argument (see below).
General requirements:
interp
,HL
ornode
Configuration file
Rendering parameters
Most parameters seen in the configuration file should be self-explanatory.
charset
can be defined as:
heaps\hxd\Charset.hx
(example "ASCII LATIN1", exact format to be defined)<texts><g id="group"><t id="textid">Some Text</t></g></texts>
, only "Some text" is considered)dfSize
SDF only: size of the distance field gradient in pixels.
Note that depending on the method of calculation other parameters can be introduced.
Packing parameters
Ideally the packing tries to output with a global image ratio close to a square. If necessary a
texWidth
parameter could be used, as a max limit to the output texture width, in pixels.For padding it is useful to separate sizes in 4 directions, for example to add effects such as drop shadows as a post-process step on the resulting texture.
Implementation
For SDF glyph rendering, an option would be to use https://github.com/Chlumsky/msdfgen, with parallel system calls to the
msdfgen
binary. The various SDF options (sdf
,psdf
,msdf
) could be exposed directly in addition tobitmap
.Another option would be to use lime.graphics.cairo for glyph rendering.
For glyph packing, see this algorithm or the implementation of fontbuilder.