Monospaced Sprite Font?

is there a way to create a monospaced spritefont from a texture2d?

I see that have to create a list of glyphs and croppings and characters?
is there a simpler way to do this by just passing a character size, map string and texture?

Well i think the easiest thing is to just use a font that is already monospaced.

If you’re intending to convert one that isn’t into a monospaced font you would probably have to alter it a bit yourself either in a program that basically makes fonts or on load or just create one that is monospaced.

.
.
Dunno if this will help but you might find it interesting. You can maybe get some insight on altering a font on load from this, which i made as much for the heck of it. As sort of a starting point so someone can see how the values coming in from a font can be manipulated. If they want to do some sort of custom manipulation of their own this might help a bit to see how a font is pieced together.

The following project goes by the following idea you make a new game1 project add the class then.

  1. load a font to the game1
  2. give it to the class instances constructor
  3. tell the class instance a directory location via the write command.
  4. close the running project.

    What you get in that directory you specified is a .cs text file.
    You add that to any game1 and it will basically let you load a hard coded font that is generated from the cs file constructor that you just made.

Links…

the github project and below this a link to another page with just a example class created from it.

example hard coded tahoma font text file generated from the above class with .cs extension.
take this then load it into a vs project its constructor returns a font that is built from the class.

Basically if you look at the glyphs and texture you can pretty much get the idea of how you would need to rescale the pixels and change the glyphs information so they are all the same width for a proportional font.
You can imagine there are probably a few ways to do what you want all with their own pro’s and cons.

this is not a sprite font though it’s a ttf font
a sprite font is something that uses sprites or a texture.

I don’t want to use a already made font because I have custom ones I have drawn onto a grid with paint.net.

this is a major problem with monogame. it’s complicated and lacks things that it should already have.
like people literally having to install monogame.extended to even draw a rectangle.

this is not a sprite font though it’s a ttf font

If you are just trying to load a ttf thats pretty easy just install it on your system and load it thru the content pipline and you get a spritefont all done easy peasy.

I don’t want to use a already made font because I have custom ones I have drawn onto a grid with paint.net.

then the previous and following applies.

Actually what i posted is not a sprite font it is a class that creates a class that will recreate the original font you had loaded all by itself in any project by generating a spritefont including the texture from what is hard coded into that class a description of a spritefont. Which is relevant because you said all you had is a image before.

But… that isn’t the point, you’re missing the point the easiest way is to build your own ttf with a tool or alter a existing one with a tool and make it monospaced.
http://www.pentacom.jp/pentacom/bitfontmaker2/

i used this then converted the result to a ttf installed it and then loaded it thru monogame that is the normal process i use for just a quick simple font. Their are far better tools. Or its possible to make something like this little app linked above, yourself that does what you are describing easily for yourself.

.

To regress

The point of that class is it shows everything that is needed manually to
(because your question seem to imply your doing it manually to me).

1) How to deconstruct a spritefont into data including the image.
2) How to construct a spritefont without loading anything at all from data.
Provided you have a full description of how to draw characters from a image you copied or made. In this case even the image was also deconstructed into data, which is why it can be constructed fully from the class.

The most important part is the texture. Its got images of letters in it, just like you would have in your image.
But you have to have a description for were each letter is in the image how big it is, what letter it actually is, ect…
Spritebatch needs data, rectangles mostly filled out that describes were each letter in that texture is.

The below shows all the major fields required per letter that is desired by a spritefont’s constructor.

        /// <summary>
        /// Holds the sprite fonts data including the pixel data.
        /// </summary>
        public class SpriteFontData
        {
            public Texture2D fontTexture;
            ...
            ...
            // per letter.
            public List<char> glyphCharacters = new List<char>(); // the character A b C ect...
            public List<Rectangle> glyphBounds = new List<Rectangle>(); // the absolute rectangle area in the image were the character is.
            public List<Rectangle> glyphCroppings = new List<Rectangle>();   
            public List<Vector3> glyphKernings = new List<Vector3>(); // left, width, right side bering
            ...

You are asking how to draw characters out of your image by using it as a spritefont.
but
A SpriteFont or any Font is more then just a image it also contains a description file or structure of all the character areas in that image.

To create a spritefont you must include all the parameters listed below.
This means if you do not want to load with the content pipeline then you must create your own file that lists characters in that image. Read the data from your file into the below types and pass them to the spritefont constructor.

I hope that makes a little more sense.

this is the font I am trying to load at runtime…

I am calculating the character width and height by dividing the texture width by 16 and height by 6 giving a range from 32-96 like on old consoles

    public class Fnt
    {
        SpriteFont font;
        public int W => font.Texture.Width  / 16;
        public int H => font.Texture.Height / 6;

        public Fnt()
        {
            List<char> chars = new List<char>();
            var tex = Game.Content.Load<Texture2D>("fnt_null");
            chars.AddRange((List<char>)Enumerable.Range(32, 96));
            font = new SpriteFont
            (
               tex,
               Enumerable.Repeat(new Rectangle(0, 0, tex.Width / 16, tex.Height / 6), 96).ToList(),
               Enumerable.Repeat(new Rectangle(0, 0, tex.Width / 16, tex.Height / 6), 96).ToList(),
               chars,
               0,
               0,
               Enumerable.Repeat(new Vector3(0, 0, 0), 96).ToList(),
               (char)0
            );
        }
        public Fnt(string filename)
        {
            if (File.Exists(filename) && Game.Initalized)
            {
                List<char> chars = new List<char>();
                var tex = Gfx.Tex(filename);
                chars.AddRange((List<char>)Enumerable.Range(32, 96));
                font = new SpriteFont
                (
                   tex,
                   Enumerable.Repeat(new Rectangle(0, 0, tex.W / 16, tex.H / 6), 96).ToList(),
                   Enumerable.Repeat(new Rectangle(0, 0, tex.W / 16, tex.H / 6), 96).ToList(),
                   chars,
                   0,
                   0,
                   Enumerable.Repeat(new Vector3(0, 0, 0), 96).ToList(),
                   (char)0
                );
            }
            else
            {
                font = Game.Content.Load<SpriteFont>("fnt_null");
            }
        }

        public static implicit operator SpriteFont(Fnt f)
        {
            return f.font;
        }
    }

You can import a texture (.png/.jpg) as a spriteFont from the pipeline. You need to have the image in a special layout (clear bounds between clyphs and fill the rest will a unique color. If all boxes are the same size then the font will be monospace). Set the importer to Texture and the processor to sprite Font.

Is that what you want? Because in the first message I think you were talking about the sprite Font constructor. That is a low level constructor that was used internally by monogame and the sprite font loader.

Recently they made it public to support some more advanced scenarios (runtime generation of sprite font). Obviously it’s not a simple method to use out of the box.

I don’t want to use the content pipeline because it creates a ton of unreadable xnb files.
I was just using temporary xnb files for null tex, snd, and fnt (texture, sound, and font).

but what I want to eventually do is load them at runtime and convert them into temporary xnb files for the life of the program. or at least do it the first time it runs and then somehow embed them in the application or 1 massive xnb file.

Do you care if the image itself is in the content folder ?

No actually that’s what I want to do.
anything without having to open the content manager and add things

Here is a start.

I just loaded the image itself thru the content manager instead of from file i figured its not a big deal. I see you know how to load it from file anyways or you can convert the whole thing at the end to self load with that github project i posted.

I didn’t handle transparency. (plenty of people can help with that too if you have a hard time).

Couple notes…

  1. The class that does the work generically… MonoSpacedFont

  2. I made this class to specifically test the image you posted … MakeTheFont_fnt_null , it just calls to the static monospacedfont class and uses its method to make the image into a font.

  3. I don’t know what the name of that font in the image is supposed to be ?
    So i just used the name of the png for the texture that you named fnt_null and then named the one class similarily to reflect what it loads, not a very good name, but anyways.

  4. Your image isn’t in the right regional order so i couldn’t use the character range directly. so in the public class MakeTheFont_fnt_null and method GetFont(Game game)
    I left a couple notes for you other wise that method would be just 2 or 3 lines.

    var chars = MonoSpacedFont.RangeToCharList(32, 96, new List());
    return MonoSpacedFont.CreateMonoSpacedFont(“fnt_null”, game, chars, 16, 6, 0, null);

instead i left notes and made a alternate way to set the characters.

        //
        // You messed this up, the character order in the image doesn't match utf16 character order.
        //
        //chars = MonoSpacedFont.RangeToCharList(32, 96, chars); 

The class method GetFont(Game game) for game when you call to it in load content just use the (this) parameter you can see how its loaded in the actual game1 content method.

Here is the game one file there is static class that is has the primary method.
The other class uses it for a specific image in the content folder to return a spritefont.

Whole thing can be copy pasted over a game1 class change the namespace to yours then add your image in the content pipeline as named. It should run the same as shown in the image i posted.

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace GuysMonoSpacedFont
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        SpriteFont myfont;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            var m = new MakeTheFont_fnt_null();
            myfont = m.GetFont(this);
        }

        protected override void UnloadContent()
        {

        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            spriteBatch.DrawString(myfont, "HELLO WORLD", new Vector2(100, 100), Color.White, 0f, Vector2.Zero, 5, SpriteEffects.None, 0);

            string dup = 
                " !" + '"' + "#$%&'()*+,-./" +
                "0123456789:;<=>?" +
                "@ABCDEFGHIJKLMNO" +
                "PQRSTUVWXYZ[" + "\\" + "]^_" +
                "`abcdefghijklmno" +
                "pqrstuvwxyz{|}~";

            spriteBatch.DrawString(myfont, dup, new Vector2(100, 200), Color.White, 0f, Vector2.Zero, 5, SpriteEffects.None, 0);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }


    public class MakeTheFont_fnt_null
    {
        public SpriteFont GetFont(Game game)
        {
            var chars = new List<char>();

            //
            // You messed this up, the character order in the image doesn't match utf16 character order.
            //
            //chars = MonoSpacedFont.RangeToCharList(32, 96, chars); 

            //
            // directly inputed
            // i cant tell what that last letter is so i skipped it.
            //
            chars = MonoSpacedFont.StringToCharList
                (
                " !" + '"' + "#$%&'()*+,-./" +
                "0123456789:;<=>?" +
                "@ABCDEFGHIJKLMNO" +
                "PQRSTUVWXYZ[" + "\\" + "]^_" +
                "`abcdefghijklmno" +
                "pqrstuvwxyz{|}~"
                , chars
                );

            return MonoSpacedFont.CreateMonoSpacedFont("fnt_null", game, chars, 16, 6, 0, null);
        }

    }

    public static class MonoSpacedFont
    {
        public static SpriteFont CreateMonoSpacedFont(string imageName, Game game, List<char> characters, int rows, int columns, int extraSpaceBetweenCharacters, char? defaultchar)
        {
            var tex = game.Content.Load<Texture2D>(imageName);
            int W = tex.Width / rows;
            int H = tex.Height / columns;
            List<Rectangle> bounds = new List<Rectangle>();
            List<Rectangle> cropping = new List<Rectangle>();
            List<Vector3> kerning = new List<Vector3>();
            for (int y = 0; y < columns; y++)
            {
                for (int x = 0; x < rows; x++)
                {
                    var posx = x * W;
                    var posy = y * H;
                    bounds.Add(new Rectangle(posx, posy, W, H));
                    cropping.Add(new Rectangle(0, 0, 0, 0));
                    kerning.Add(new Vector3(0, W, 0));
                }
            }
            return new SpriteFont
            (
               tex,
               bounds,
               cropping,
               characters,
               H,
               extraSpaceBetweenCharacters,
               kerning,
               defaultchar
            );
        }

        public static List<char> StringToCharList(string s, List<char> charlist)
        {
            foreach (char c in s)
                charlist.Add(c);
            return charlist;
        }
        public static List<char> RangeToCharList(int start, int end, List<char> charlist)
        {
            for (int i = start; i < end; i++)
                charlist.Add((char)i);
            return charlist;
        }
    }

}

Once you get the kinks out. You could use my github project i posted at the begining to transform the finished result into a loadable class file if you wanted to as well its pretty straightforward just give it the spritefont you just made and it will turn it all into a class that self creates the whole spritefont.