Font runtime rendering?

Hi There,

I’m new to monogame and was wondering if there a way to render TTF fonts on runtime? I’m asking this because I want to set the size variable dynamically depending on the screen-size and some local scale variables. Also being able to play around with the font weight and italic options on runtime would be nice.

It seems that if I want to do this with the Content Pipeline then I have to render the font N times. (say from 8-72). This seems highly inefficient.

For my graphics I’m not using the Content Pipeline at all. This is because i’m building a 2d game engine for my game(s) and i am building my atlases on runtime. (based on the max_texture_size, stuff as many groups on a single texture). And a small minor proportion of my graphics are vector based and rendered at runtime.

Textures have: Texture2D.FromStream() and Texture2D.SetData()
Audio has: SoundEffect.FromStream()

But fonts do not seem to have something like this :frowning: Which is inconsistent with the other assets.

What would you recommend me do? Still use the Content Pipeline just for my fonts and render N copies of it, or introduce a third party font library? Or perhaps somethings else?

Thanks!

A long time ago with XNA I did some similar research. I seem to recall discovering that you can do runtime content pipeline loading. Google probably has a lot of hits for this, so that’s one option.

The advantage here is that you can get the font you want, when you need it, but the downside is that you can end up loading many, many fonts throughout the runtime of your program. This can lead to a lot of unnecessary memory overhead. You could write a manager to unload fonts that haven’t been used in a while I suppose, but this could be a pain.

The extreme alternative of this is to just load a single font of some size, then let a SpriteBatch handle the scaling for you. This lets you avoid loading a lot of fonts via your content pipeline and having them hanging out in memory, but it can also result in a lack of clarity for your scaled fonts. Through some testing I did a while back, scaling was pretty good within a certain amount of the font size, but after that you start to get some pixelation, even with texture filtering.

I never did implement this, but my plan at the time was to create some font breakpoints. Like, create spritefonts for my text at a fixed set of sizes. Then use spritebatch scaling to get the inbetween sizes. So like, have fonts built-in for sizes { 12, 24, 32, 72 }. Then if I needed, say, a font size of 16, I would just pick the 12 font size and scale it up (or the 24 font size and scale it down.

This all to say, I don’t really know what the best solution is, but those are some possible ideas to explore/play with :slight_smile: Good luck!

1 Like

@Trinith Thanks a lot for the great reply!!!

If the runtime Content Pipeline is not disposing the fonts correctly out of the box, then I am probably going to use the “break point” solution. If I only downscale the blur should be kept to a bare minimal.

Still it would be great and consistent if in future versions the fonts would have the same FromStream method as the other assets.

Anyways, Thanks alot!

I just use GDI. Flexible enough for DPI scaling.

Sorry, that’s not what I mean to imply. I would assume that this works, but I believe you would have to manually request that those assets unload, which is still a technical challenge for you. Not insurmountable by any stretch, but definitely adds complexity. It really boils down to your needs :slight_smile:

As for loading from a stream, I think it’s a little different with fonts. For all the content pipeline stuff, I think the pipeline manager does “stuff” to the files to manipulate them into a better set of data for use with MonoGame. Still though, at the end of the day, it’s just data so reading a texture of an audio file in from a stream can still give you raw data to work with.

A SpriteFont though is a little different in that it’s actually generating a spritesheet of characters for you. I believe that SpriteBatch.DrawString is just a special convenience method that utilizes that spritesheet and draws out a string for you. Not saying it still couldn’t be generated at runtime (I honestly have no idea the underlying mechanism), just that I think you can’t really compare Texture2D.FromStream to a hypothetical SpriteFont.FromStream :slight_smile:

That’s an interesting approach! Correct me if I’m wrong, but you’d lose the ability to control the order of text rendering (ie, you couldn’t draw text partially behind a texture), but that could easily be something that doesn’t really matter that much in most applications.

The glyphs of the fonts are rendered to the parameters set in the .spritefont file to a raster. Then a atlas/index is used to draw the characters on demand. (drawstring). This is basically how all font rendering works. But I see no reason why a platform like MonoGame can’t provide something like this:

// Initialize the font and prepare it to be rendered to a texture
var font = SpriteFont.FromStream(Stream path);
// Create the raster.
font.Render(int size, bool bold, bool italic);
// Draw
spriteBatch.DrawString(font, "Hello World", new Vector2(0, 0), Color.Black);

Basically the .spritefont files with the hard coded size and decoration parameters is really not desirable. Also the whole framework is - not low but mid level - code eccentric, I already wrote: Dynamic runtime Atlasing, Tilemap, Sprite-Classes, Collisions and a lot of little classes… But for the fonts I need to rely on an outside parameter file. To me that really seems out of place and I really can’t figure out why anyone would want it configured like that in retrospective to the rest of the framework. Also there are a lot of resolutions/aspect-ratios these days… If you like me and want to support them all then you going to need to set the font size on runtime based upon the screen/window resolution…

If there are no issues with the runtime Content Pipeline… Then I will defintly check that out. So thanks for correcting me. :smiley:

You can probably just render it to a bitmap and then use SetData on a Texture2D to upload the pixels :wink: But doing it like that the downsize might me performance when you need to change the string a lot! spriteBatch.DrawString() is a way more effective way of doing it!.. Still it might be worth checking out though.

@live627 Out of curiosity… Is GDI available on all platforms? (I believe Android does not have it, perhaps other also dont’)

I’m only developing on Windows, therefore, GDI is a no-brainier for me. I don’t know (or care) about platform compatibility.

I simply render to a bitmap, then copy to XNA with Texture2D.FromStream() via a regular memory stream.

1 Like

I also would like to be able to load SpriteFonts at runtime and change their properties, including font size. Do you think you can open an issue and see what they think?

Hi there: Judging by this Github thread, they are fully aware of both the bennefits and the downside as is:: https://github.com/MonoGame/MonoGame/issues/4796

But we can always try! Personally I think the way it works now is a design flaw. We are doing all the arithmetics for translations, scale and sizes of our games on runtime, but the fonts properties need to be predetermined in advance and hard-coded in a external file :disappointed:

There’s a downside to using uncompressed assets, but I think that’s on the responsibility of the game developers. The current develop version does have a public SpriteFont constructor, so you should be able to use that. I would prefer if we had a FromStream() method, though. Have you tried importing MonoGame.Framework.Content.Pipeline.dll and loading fonts with that?

I absolutely agree with you. Also, compression is not the biggest problem. Fonts are really not that big (depending on the fontsize they can be bigger when rendered) and PNG and OGG are already compressed. The biggest advantage of the Content Pipeline is that all assets are preprocessed and good to go! But rendering those files on runtime can be time consuming. I personally do those things in a init script/function and show a splash while waiting.

Still have to look into that… But at a first glance it seems poorly documented on a correct way of using it. It seems to be implemented by this class: PipelineManager

The constructor looks like this.

public PipelineManager(string projectDir, string outputDir, string intermediateDir)

But I don’t want to use directories! I want to use Stream/byte[]

Maybe I’m still going to use the breakpoint solution of @Trinith … That way I can at-least continue for now. I can always reconfigure my code later. Hopefully in the future we can use the fonts on runtime instead of only on compile time.

I’ve just created a font from 8-308 pixels (and yes, i’m going to need a font of 300px for higher resolutions) with an increment of 10 pixels. This adds 70mb to the distribution of my game and is totally unacceptable. Among desktop targets I want to target Android + IOS, so I want to keep the distribution as small as possible! My graphic assets are only 55mb at this moment. So adding a extra 70 just for fonts is ridiculous. .

Also this is not the only font I want to import. So that would be 70 * number of fonts = ridiculous.

Before deciding on going up in 10 pt increments, maybe do some experimentation to see how well the scaling works. You might find you need significantly less increments, especially as you go up in font size since, when you have more pixels to work with, the result of scaling is usually better.

If you’re not a fan still that’s cool, it’s all about your needs. Definitely look into runtime font compilation, just make sure you unload fonts you’re not using anymore to keep your memory footprint down. I’m not well versed in such structures, but maybe some kind of frequency based cache approach? I dunno… all I’m saying is that if you’re worried about 70 fonts taking up a lot of memory, it’s going to be much, much worse if you’re dynamically loading fonts during run-time.

Also, for what it’s worth, this is no different than if you just loaded them from a stream. Every time you load a font it’s going to allocate some memory. Unless you’re requesting an unload of these assets, they’re going to pile up at runtime. Same with textures and audio… those just get loaded less frequently since for fonts, you’re going to be loading a new one every time you want to scale. So yea, this issue has nothing to do with the content pipeline… in fact, the content pipeline is actually saving you memory by doing a better job of compressing assets for the target platform (per one of the links posted in that github issue you linked above).

I basically do this with everything… So why not with the fonts? I even went as far to create a pooling system so that my objects can be requested and released (to the pool) in order to not keep creating new Garbage(); Which is a major optimization for recycling objects and ducking the Garbage Collector. Also I have a very sophisticated Atlas that shares as much sprites/animations/tilemaps on one texture by looking at the max_texture_size of the device at runtime. I want to do same things for fonts, but if there’s no API for generating them then I cant do that.

I absolutely disagree! It has everything to do with the Content Pipeline. And also you assume too much. I’m not going to use the 70 generated fonts, just a sub-selection of them. But, I will only know on runtime - per device - what the sub-selection will be. So in order to have them all available I have to generate them all so that i can accommodate all devices.

Resolutions that i wish to support go from 480 pixels up to 2160 pixels in height plus some world scaling set per resolution. This will end up in just a couple of font-sizes that i need - per device. But again, I will only know this at runtime.

Since you think its not the Content Pipeline, then by all means explain how this scenario is suppose to work with it…!?

First of all, It introduces a lot more of storage of the xnb files. Example: fa308.xnb = 8.198mb, the font file is 120kb. So that’s a big price tag on the storrage. And for a platform that’s also targeting smart devices it seems out of place… Secondly, “You are going to use RAM anyways…”. As long as everything is nicely cleaned and disposed, I really don’t think it’s much of a argument. As soon as the font is on the texture (VRAM), then you just dispose() the ram.

The only real argument is that it reduces runtime processing. But I do these things on initialization, not on updates so I really don’t care that some splash image is showing a whole extra second!

Also, this is the first framework/engine/library that I have encountered that does not allow you to set the font-size on runtime… We are programmers, not designers if you know what i mean.!

Neat :slight_smile:

Using the content pipeline to dynamically create a spritefont for you at runtime doesn’t really feel like it’s going to do anything terribly differently than a SpriteFont.FromStream method would do. It’s still got to build a texture containing all of the characters you want from the specified font. It’s going to store it completely in memory without generating the xnb file, but still given that you can delete that file later, it shouldn’t be all that bad. It’s a hoop you have to jump through because you have to write this code yourself instead of having it supplied from MonoGame, but I dunno, it doesn’t seem that big of a hurdle, especially since it sounds like you’ve got a mechanism in place for managing assets.

It’s not ideal for your case, but the reasons for why MonoGame stuck with the Content Pipeline seemed reasonable. They also provide the tools you need to work around this, if you so desire.

I’m wondering if this might not be the best idea. Assuming for a second that you’re not going with a breakpoint approach and instead do pure dynamic loading, this is a lot of fonts to pre-load! I can see your concerns. Out of curiosity, have you done any experimentation with some kind of “just in time” loading? Loading everything at once might add that extra second or two to an initialization, but if it’s a few milliseconds inside a single update among many to load just the font you need as you’re drawing, would that be so bad?

This is speculation of course, I don’t know the answers to these questions. Definitely things that might be worth an experiment or two :slight_smile:

I can definitely think of a lot of cases where the font you want isn’t known at compile time. I do understand why you want this functionality and I agree that it would be nice, but I also understand that for most games, knowing your font ahead of time is actually pretty reasonable. It’s only when you want to create supporting applications/designers for game assets that this becomes a bigger issue.

Most of my other experience is in using stuff like OpenGL (which I don’t think has any direct built-in text support), or looking at engines like Unity. For the latter, from what I can see, they’re doing all the stuff that you would be building for you… but I don’t think Unity and MonoGame are the same kind of thing.

@Trinith Thanks for the reply!

Excactly! As soon as its on the texture (VRAM) you can dispose the ram copy!, So process the font, feed the Texture2D and then dispose() the ram. This will not have no lasting impact on the ram. It can all be done in the same function.

Too me? Yet it does. :smiley: If you know in advanced about the font’s properties then just render it in advanced. And a couple of milliseconds can be a lot on a busy update/draw ecosystem. I always try and keep an eye out for performance: Only use new() in constructors, try and use StringBuilders where possible, use Pooling where possible, Texture Sharing and anything else I can think of.

But back to the topic, is “MonoGame.Framework.Content.Pipeline.dll” available on all platforms? I’m asking because it’s written for Desktop usage. It just might have some foreign code or API calls that are not supported everywhere. It would be a shame diving into it only to find out it will not work on Android/IOS/WindowStore.

I was thinking to just wrap some old c++ code I have for rendering fonts based upon stb_truetype. But while setting up for windows desktop I was fearing that it might not work on Android & IOS. I basically have no clue how to set up c++ for usage in C# on those platforms. It’s worth checking out though.

Changes are that i’m still going to use “breakpoints” solution. In which case I will just accept my personal discomfort with it.

Anyways, thank!

Just found out that the answer is no!. Its only for Desktop (Windows, Mac, Linux). Not for Smart Devices

So that options is no good for me. Its either the “breakpoints” solution or introducing a 3trd party library. This explains why there is no font builder at runtime… It’s probably a foreign library.! or API (eg: GDI) which will not work on all platforms.!

Definitely important! On the flip side though, from experience, I’ve found I can get caught in a performance trap. I’ve over-engineered stuff in the past and spent too much effort on something I didn’t need. Lately I’ve been trying to follow a more balanced approach.

I’m not saying that’s the case here, just that if the overhead of dynamically loading a font on demand during a single update, then caching it for all future updates, might actually fit within your performance expectations. Only you will know what’s best for your application :slight_smile:

Out of curiosity, what are you building?

I’m not sure. I’m actually interested enough in this topic that I started to do some research (then rather forcefully pulled myself back to focus on the task I’m working on, lol). I found that in the old XNA environment, this was definitely coupled to the Windows platform. I’m not sure about MonoGame though since it does do things a little differently. If MSBUILD is involved in the process, you might be in trouble for cross platform. You’d need to do some digging.

Multi platform 2D game engine for hosting my own games. Primary targets are Smart Devices and Desktops. I’ve started out with C++ from scratch, but a engine like that is too much work to also develop my own games for it. After that I tried Haxe. Was very impressed by the language and portability, but was less impressed by the rendering performance. Then I did some minor tests on Unity, libGDX and MonoGame. Unity was nice but under performing on Smart Devices (atleast to my own standards) GDX was not bad and a potential candidate, but I personally prefer C# over Java. Also, MonoGame has the out-of-the-box solution for DirectX render for windows and WindowsStore support.

I’ve been add it now for 2 months. The majority for the Graphics, Logic, Physics and Hierarchy (Scenes, Layers, Objects, etc) is about done. Still need to do Audio, Platform Specifics for Mac & IOS and FONTS :smiley:

I have a build system made in LUA that builds the games out of templates and creates my assets. While making that I didn’t figure that the fonts would form a problem :smiley: If i’m going to use the Content Pipeline I probably am going to generate the .spritefont files from LUA based on a configure file that all my games have.

Otherwise use C++. But since I’m new to Xamarin/Mono/MonoGame i’m not to eager to jump into that boat :wink: It’s not the C++ what i’m afraid of, but integrating it on all platforms can be a pain!

But, thanks for asking! And I also like to know what you are building?

Cool :slight_smile:

For me, I’m doing somewhat similar actually but going about it in a somewhat different way. I just picked some fairly simple game project and used that to direct my efforts. Anything I need to accomplish the game, I create. If I don’t need it, I don’t make it… I’ll do that when some future title demands it.

It’s going well, but taking forever! Mostly because I decided that, at the outset of this project, I wanted to make everything fully unit tested. The downside to this approach is, as I said, the amount of time it takes. I tend to follow a prototype and port approach so I can figure out how I want to do something, then turn that into testable code. Prototypes often take very little time, but moving over to “production” code takes much longer. The upside though is that in making sure everything is testable, it leads me to make much better code design decisions than if I just wrote it without focusing on testing. It’s also saved me a ton of time on some refactor work I’ve needed to do, since my tests really help me direct my attention to areas that break when I make changes.

I’m almost done my first title and have plans to move on to another one after that, but we’ll see how it goes. Mostly this is a “life goal” endeavor as well as hoping I can build some good experience, and maybe make a little bit selling copies if possible. The first title is just a simple app based on a board game called Mastermind. It’s not terribly complex but was a good starting point to drive my engine requirements. If you’re at all interested, you can check me out on Facebook here: https://www.facebook.com/ArbitraryPixelSoftware/