Font runtime rendering?

@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: Redirecting...

Sorry friend… I’m not on FaceBook… But board games can be fun to code. Thanks for sharing, Hope it works out for you!

I’m curious about the latter. How does Unity and Microsoft Word handle adjusting font size easily?

@Kimimaru Fonts are rendered the same everywhere. The the font is rendered by request with size and decoration parameters. That creates a bitmap containing the glyphs and an atlas of rects describing it. (then on a GL/DX environment the bitmap is loaded as a texture on vram) When you want to print a string the function that does that iterates over the characters and foreach character it finds the belonging rect will be copied to the screen/buffer.

Basically the content pipeline creates the texture and the atlas on compile-time. This disallows you from creating it on runtime. After researching this a bit, this is probably because they are using a third party (c++) library, or API calls (eg. GDI) which are not supported on all platforms.

So either introduce your own font renderer (I personally would go with stb_trutype), or scale the pre-processed spritefonts with the spritebatch.

You can use the alternative I use.

I gave up with spritefonts for anything other than debug a long time ago. Instead I swapped to signed distance field fonts.

There is a freeware tool available (sorry cannot remember the name of it at the moment) which generates the required texture and supporting text file.

It requires a renderer that can render quads at floating point positions, so you cannot use spritebatch, but that is trivial to create.

Then a custom shader. Which is simple.

`float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float mask = tex2D(tex,input.UV).a;
float4 clr;

clr.rgb = colour.rgb;

if( mask < 0.4 )  
	discard;
else  
	clr.a = 1.0;

// do some anti-aliasing
clr.a *= smoothstep(0.125, 1.00, mask);

return clr;

}

`
The good thing is that the font can be scaled at runtime to pretty much any size you want.

You can also change the shader to do things like shadows, glows, borders, all sorts of things to liven up you text rendering.

If you think it is worthwhile I could package my stuff up and publish it somewhere, but it is really easy to do.

Anyway, might be a way to solve your problem quickly.

Good luck.

Stainless

1 Like

@StainlessTobii
Hi,

Thanks for your response! Your sollution seems pretty decent! But since my last post i’ve already implemented the “break point” sollution in my game engine with support for:

  • Single Line
  • Multi Line
  • Render in Rectangle Area’s
  • Alignments (left, center, right) (using MesureString())

The resolving text is integrated in my engine eco-system and it would be a shame making it this nice and then not use it! But your solution still might help others, perhaps you can still make it available on request for others!

Thanks a lot for sharing!

It requires a renderer that can render quads at floating point positions,

I dunno about the loading but spritebatch itself internally renders all the glyphs as quads.

When you make a call to spritebatch’s drawstring the letter evaluates to a rectangle that is stored in the spritefonts glyphs but that rectangle is divided by the images width and height and is turned into a floating point quad.

You can actually peel out the glyphs redo them and replace them along with the texture in the spritefont.
If you were so inclined to go thru all that.
In the case of getting rid of different sized fonts and just loading the largest ones basically you could then just rescale them down in both the glyph and texture with get set data and create them on the fly i suppose. You would have to keep track of the textures you created to dispose of them though on game end.

Hi willmotil,

You don’t have a method on spritebatch that takes a RectangleF as input, so what happens is the glyphs are slightly out of position and you get little gaps in words that just look awful.

A quad renderer is so much easier to work with, and you can batch it just like spritebatch.

Using signed distance field fonts you only have, want, and need a single texture. That’s a big thing if you want multiple font faces in your game. The less texture space we use for font rendering the better in all games, then we can have 4K textures where we really need them, like skin shaders.

I will see if I can strip my stuff out into a demo and publish it somewhere.

You don’t have a method on spritebatch that takes a RectangleF as input, so what happens is the glyphs are slightly out of position and you get little gaps in words that just look awful.

Are the physical pixels that make up your screen or your image described or stored discrete units ?.. yes they are so they ultimately equate to integer values. The spritefont.xml that the pipeline produces has a field that allows you to turn on kerning which you should do.

A quad renderer is so much easier to work with, and you can batch it just like spritebatch.

That maybe true but have you compared the raw speed you get with your renderer to spritebatch drawstring ?.

Using signed distance field fonts you only have, want, and need a
single texture. That’s a big thing if you want multiple font faces in
your game. The less texture space we use for font rendering the better
in all games, then we can have 4K textures where we really need them,
like skin shaders.

Well im not familar with signed distance fields.
If the goal is to eliminate loading multiple resolution fonts with just one im all for that.

The spritefont class is intended for speed it was never intended to handle a game that wants to use 10 different fonts. That said if you want this in monogame we would first have to know how to incorporate it into spritebatch and if it is possible jjag or nkast did the optimizing on spritebatch i did some initial work on unrolling the matrices but i put up all my working code with simplified comparisons and demo examples. It’s open source meaning anyone can contribute to limits of there ability to do so.

Like i said though internally spritebatch is just using what amounts to floats,

In truth using a rectangleF is a non issue once you realize all textures have pixel width and height and every quad translates to physical pixel coordinates.

/// <summary>
/// Submit a text string of sprites for drawing in the current batch.
/// </summary>
/// <param name="spriteFont">A font.</param>
/// <param name="text">The text which will be drawn.</param>
/// <param name="position">The drawing location on screen.</param>
/// <param name="color">A color mask.</param>
	public unsafe void DrawString (SpriteFont spriteFont, string text, Vector2 position, Color color)
	{
    CheckValid(spriteFont, text);
    
    float sortKey = (_sortMode == SpriteSortMode.Texture) ? spriteFont.Texture.SortingKey : 0;

    var offset = Vector2.Zero;
    var firstGlyphOfLine = true;

    fixed (SpriteFont.Glyph* pGlyphs = spriteFont.Glyphs)
    for (var i = 0; i < text.Length; ++i)
    {
        var c = text[i];

        if (c == '\r')
            continue;

        if (c == '\n')
        {
            offset.X = 0;
            offset.Y += spriteFont.LineSpacing;
            firstGlyphOfLine = true;
            continue;
        }

        var currentGlyphIndex = spriteFont.GetGlyphIndexOrDefault(c);
        var pCurrentGlyph = pGlyphs + currentGlyphIndex;

        // The first character on a line might have a negative left side bearing.
        // In this scenario, SpriteBatch/SpriteFont normally offset the text to the right,
        //  so that text does not hang off the left side of its rectangle.
        if (firstGlyphOfLine)
        {
            offset.X = Math.Max(pCurrentGlyph->LeftSideBearing, 0);
            firstGlyphOfLine = false;
        }
        else
        {
            offset.X += spriteFont.Spacing + pCurrentGlyph->LeftSideBearing;
        }

        var p = offset;                
        p.X += pCurrentGlyph->Cropping.X;
        p.Y += pCurrentGlyph->Cropping.Y;
        p += position;

        var item = _batcher.CreateBatchItem();
        item.Texture = spriteFont.Texture;
        item.SortKey = sortKey;
    
        _texCoordTL.X = pCurrentGlyph->BoundsInTexture.X * spriteFont.Texture.TexelWidth;
        _texCoordTL.Y = pCurrentGlyph->BoundsInTexture.Y * spriteFont.Texture.TexelHeight;
        _texCoordBR.X = (pCurrentGlyph->BoundsInTexture.X + pCurrentGlyph->BoundsInTexture.Width) * spriteFont.Texture.TexelWidth;
        _texCoordBR.Y = (pCurrentGlyph->BoundsInTexture.Y + pCurrentGlyph->BoundsInTexture.Height) * spriteFont.Texture.TexelHeight;

        item.Set(p.X,
                 p.Y,
                 pCurrentGlyph->BoundsInTexture.Width,
                 pCurrentGlyph->BoundsInTexture.Height,
                 color,
                 _texCoordTL,
                 _texCoordBR,
                 0);
        
        offset.X += pCurrentGlyph->Width + pCurrentGlyph->RightSideBearing;
    }

		// We need to flush if we're using Immediate sort mode.
		FlushIfNeeded();

}

No mate, you have got it all wrong.

Say I am displaying a string “Hello”

In the font definition the width of the H character is 16.25 pixels. I draw the H glyph in the correct place, then come to draw the e glyph.

Using spritebatch I would have to display it 16 pixels away from the start position, and the space between the chars is reduced. This can even result in glyph’s overlapping.

Using a glyph batch, which is just as fast as spritebatch, the glyph is in the correct position, just one of the pixels gets written to twice to handle the overlap when we get to physical pixels.

However the very nature of signed distance fields means this is not visible.

When I first wrote a SDF font renderer, I thought like you, but when I actually tested it, the result was garbage. It took me a couple of hours to figure out that problem. I also screwed up by having point sampling enabled, but that’s another story. :smile:

I have finished a quick demo which shows 4 different shaders (normal, inverse, shadow, and outline) working with the same two SDF fonts.

Displaying at 4 different font sizes.

Just got to find somewhere to put it.

Okay decided just to stick it on my website.

example project

I use google drive its good for small projects.

Anyways i still don’t see the big advantage. Or any problem with glyph’s overlapping, using spritebatch.
My complaint with spritebatch isnt quality its the lack of automatic mipmaping when scaling down.
But that is being pretty nit picky.

Its like a 45 point sized font (but the bigger the better with spritefont), that is resolution scaled via a design time w h proportion + user scaled. With user resizing on in a shrunk window.

Looking at that code i doubt its anywere near as fast as spritebatch. You would have to do some testing to make that claim you might be suprised what you find.

You can send in effects to spritebatch begin.
As well as a matrix, meaning you can use it for 3d text. ect…

Also as far as garbage all numerical text will generate it.

            spriteBatch.Begin();
            GraphicsDevice.SamplerStates[0] = new SamplerState() { Filter = TextureFilter.Point, AddressU = TextureAddressMode.Clamp, AddressV = TextureAddressMode.Clamp };

            Vector2 txPos;
            Vector2 txSize;

            txPos = VirtualPosToScreen(.025f, .33f);
            txSize = ScreenReScale(.5f ,1f);
            spriteBatch.DrawString(regfont, "Verdana mg scale .5, 1f", txPos, Color.Moccasin, 0f, Vector2.Zero, txSize, SpriteEffects.None, 0f);

            txPos = VirtualPosToScreen(.025f, .45f);
            txSize = ScreenReScale(.5f ,.75f);
            spriteBatch.DrawString(regfont, "Verdana mg scale  .5, .75", txPos, Color.Moccasin, 0f, Vector2.Zero, txSize, SpriteEffects.None, 0f);

            txPos = VirtualPosToScreen(.025f, .55f);
            txSize = ScreenReScale(.5f ,.5f);
            spriteBatch.DrawString(regfont, "Verdana mg scale .5, .5", txPos, Color.Moccasin, 0f, Vector2.Zero, txSize, SpriteEffects.None, 0f);


            // draw the font.
            spriteBatch.Draw(regfont.Texture, new Vector2(400, 400), Color.Blue);

            spriteBatch.End();

Dunno how you can draw bottom up ah that seems so un-natural to me.

        Vector2 VirtualPosToScreen(float x, float y)
        {
            var v = new Vector2(x, y);
             return v * new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
        }
        Vector2 ScreenReScale(float x, float y)
        {
            var v = new Vector2(x, y);
            Vector2 screenScaling = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height) / new Vector2(800f, 600f);
            return v * screenScaling;
        }
        Vector2 ScreenReScale(float s)
        {
            Vector2 screenScaling = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height) / new Vector2(800f, 600f);
            return s * screenScaling;
        }

Sorry im not trying to put it down or boast about the current spritebatch its got drawbacks, im just saying this.

That is nice but its not as simple or functional and i doubt its as fast as the current implementation and adding it in would be a lot of work to bring it on par with spritebatch, more then what is shown in that project far far more.

The image you have posted shows the massive problem that stops me using this technique.

Scaling artifacts. They are everywhere. Which for me makes it un-usable for font rendering.

The beauty of Signed Distance Field Fonts is you don’t get scaling artifacts. You get crisp clean edges. You do get a certain amount of fading out of text when you down sample a lot, but it’s still crisp and clean.

We can argue about what is faster, a quad batch or spritebatch all day. Maybe that is a good argument we should have somewhere. We may come up with some ideas for speeding up spritebatch, or getting rid of scaling artifacts, or something. I don’t think this thread is the right place for that though. ( I also think it’s going to come down to wavefronts and other GPU specifics which don’t fit the Monogame ethos… but that’s another topic). :smiley:

Anyway, anyone interested in font rendering now has a thread to read :grin:

OMG, I have created a monster :imp: (:P)

A wild solution has appeared xD

I played with your code, and got it to generate less garbage just by moving

RasterizerState stat = new RasterizerState(); SamplerState ss = new SamplerState();

to fields.

The GC was called enough that CPU time was a bit higher. Not ideal.

After my change, less garbage is spewn out.

Hope that your game may benefit.

There are historical reasons why Microsoft used the Content Pipeline for Fonts:

  • Licensing. TrueType fonts have permissions associated with them indicating how they can be used without paying royalties. The one required to distribute a ttf file, Installable, was not granted on most fonts shipped with Windows.
  • Cross-Platform. By integrating rasterized fonts as textures, the fonts will have a consistent look no matter what fonts are installed locally.
    I addition to the points above MonoGame, must be able to maintain consistency across many different platforms, each with it’s own font processing/rendering capabilities.

Please note that anything above ~72 points (not px) is simply a scaled version of the 72 font. TTFs include hints to apply when rendered small 6-8, medium 10-15, and large fonts. The exact sizes and number of divisions vary with each font, but were defined with printing in mind, therefore, larger font sizes return a scaled version of the largest hint available.
My recommendations for divisions would be 8,9,10,12,16,18,24,36,72 and scaling when needed. That should be around 1 MB per font.
My solution to this problem was to break up the distributions by screen size. For example, on Android, I created builds of the app targeting small screens with small fonts(8,12) … Through 4k TV(74,96). Similar on IOS. Desktop users typically don’t care about file size.

All fonts are not rendered the same everywhere. They are similar to the process you describe, but each vendor has it’s own implementation, API and font formats(See Color fonts). For example, the emojis you utilized in previous posts were converted to PNGs by the web server and not rendered as a font.

My point is run-time font rendering has its place(CJK and emoji, Where sizes balloon by combinations.) In my opinion, it is not needed for general use within the framework, as there are other viable solutions available.

Thanks, I did not know that, I always just thought that it’s made out of vectors which can be rasterized to any size. Also it seems very outdated in a mush higher pixel density era we are living in, which presumably will keep evolving in the future.

Implementations only differ in features. The core process is the same, so generalizing a bit does not seem out of place.

They are converted by the browser and I don’t see what a feature like that has to do with “font rendering”. It just replace some text by images and works on a different level (post font rendering) then the fonts.

:0) --> <img ... />

Is not font rendering but search and replace.