public static BitmapFont ReadXML(TextReader textReader)
        {
            var bitmapFont = new BitmapFont();

            var document = XDocument.Load(textReader);

            var fontElement = document.Element("font");

            if (fontElement == null)
            {
                throw new InvalidDataException("Missing root font element in XML file.");
            }

            // Info

            var infoElement = fontElement.Element("info");

            if (infoElement != null)
            {
                bitmapFont.Info = BitmapFontInfo.ReadXML(infoElement);
            }

            // Common

            var pages = 0;

            var commonElement = fontElement.Element("common");

            if (commonElement != null)
            {
                bitmapFont.Common = BitmapFontCommon.ReadXML(commonElement, out pages);
            }

            // Pages

            var pagesElement = fontElement.Element("pages");

            if (pagesElement != null)
            {
                bitmapFont.Pages = new Dictionary <int, string>(pages);

                foreach (var pageElement in pagesElement.Elements("page"))
                {
                    var id   = (int?)pageElement.Attribute("id") ?? 0;
                    var name = (string)pageElement.Attribute("file");
                    bitmapFont.Pages[id] = name;
                }
            }

            // Characters

            var charactersElement = fontElement.Element("chars");

            if (charactersElement != null)
            {
                var count = (int?)charactersElement.Attribute("count") ?? 0;

                bitmapFont.Characters = new Dictionary <int, Character>(count);

                foreach (var characterElement in charactersElement.Elements("char"))
                {
                    var character = Character.ReadXML(characterElement, out var id);
                    bitmapFont.Characters[id] = character;
                }
            }

            // Kernings

            var kerningsElement = fontElement.Element("kernings");

            if (kerningsElement != null)
            {
                var count = (int?)kerningsElement.Attribute("count") ?? 0;

                bitmapFont.KerningPairs = new Dictionary <KerningPair, int>(count);

                foreach (var kerningElement in kerningsElement.Elements("kerning"))
                {
                    var kerningPair = KerningPair.ReadXML(kerningElement, out var amount);
                    if (bitmapFont.KerningPairs.ContainsKey(kerningPair))
                    {
                        continue;
                    }
                    bitmapFont.KerningPairs[kerningPair] = amount;
                }
            }

            return(bitmapFont);
        }
        public static BitmapFont ReadText(TextReader textReader)
        {
            var bitmapFont = new BitmapFont();

            while (textReader.Peek() != -1)
            {
                var lineSegments = TextFormatUtility.GetSegments(textReader.ReadLine());

                switch (lineSegments[0])
                {
                case "info":
                {
                    bitmapFont.Info = BitmapFontInfo.ReadText(lineSegments);
                    break;
                }

                case "common":
                {
                    bitmapFont.Common = BitmapFontCommon.ReadText(lineSegments, out var pageCount);
                    bitmapFont.Pages  = new Dictionary <int, string>(pageCount);
                    break;
                }

                case "page":
                {
                    bitmapFont.Pages = bitmapFont.Pages ?? new Dictionary <int, string>();
                    var id   = TextFormatUtility.ReadInt("id", lineSegments);
                    var file = TextFormatUtility.ReadString("file", lineSegments);
                    bitmapFont.Pages[id] = file;
                    break;
                }

                case "chars":
                {
                    var count = TextFormatUtility.ReadInt("count", lineSegments);

                    bitmapFont.Characters = new Dictionary <int, Character>(count);

                    for (var i = 0; i < count; i++)
                    {
                        var characterLineSegments = TextFormatUtility.GetSegments(textReader.ReadLine());
                        var character             = Character.ReadText(characterLineSegments, out var id);
                        bitmapFont.Characters[id] = character;
                    }

                    break;
                }

                case "kernings":
                {
                    var count = TextFormatUtility.ReadInt("count", lineSegments);

                    bitmapFont.KerningPairs = new Dictionary <KerningPair, int>(count);

                    for (var i = 0; i < count; i++)
                    {
                        var kerningLineSegments = TextFormatUtility.GetSegments(textReader.ReadLine());
                        var kerningPair         = KerningPair.ReadText(kerningLineSegments, out var amount);
                        if (bitmapFont.KerningPairs.ContainsKey(kerningPair))
                        {
                            continue;
                        }
                        bitmapFont.KerningPairs[kerningPair] = amount;
                    }

                    break;
                }
                }
            }

            return(bitmapFont);
        }
        public static BitmapFont ReadBinary(BinaryReader binaryReader)
        {
            var bitmapFont = new BitmapFont();

            var magicOne   = binaryReader.ReadByte();
            var magicTwo   = binaryReader.ReadByte();
            var magicThree = binaryReader.ReadByte();

            if (magicOne != MagicOne || magicTwo != MagicTwo || magicThree != MagicThree)
            {
                throw new InvalidDataException("File is not an FNT bitmap font or it is not in the binary format.");
            }

            if (binaryReader.ReadByte() != ImplementedVersion)
            {
                throw new InvalidDataException("The version specified is different from the implemented version.");
            }

            var pageCount = 0;

            while (binaryReader.PeekChar() != -1)
            {
                var blockID = (BlockID)binaryReader.ReadByte();

                switch (blockID)
                {
                case BlockID.Info:
                {
                    bitmapFont.Info = BitmapFontInfo.ReadBinary(binaryReader);
                    break;
                }

                case BlockID.Common:
                {
                    bitmapFont.Common = BitmapFontCommon.ReadBinary(binaryReader, out pageCount);
                    break;
                }

                case BlockID.Pages:
                {
                    binaryReader.ReadInt32();

                    bitmapFont.Pages = new Dictionary <int, string>(pageCount);

                    for (var i = 0; i < pageCount; i++)
                    {
                        bitmapFont.Pages[i] = binaryReader.ReadNullTerminatedString();
                    }

                    break;
                }

                case BlockID.Characters:
                {
                    var characterBlockSize = binaryReader.ReadInt32();

                    if (characterBlockSize % Character.SizeInBytes != 0)
                    {
                        throw new InvalidDataException("Invalid character block size.");
                    }

                    var characterCount = characterBlockSize / Character.SizeInBytes;

                    bitmapFont.Characters = new Dictionary <int, Character>(characterCount);

                    for (var i = 0; i < characterCount; i++)
                    {
                        var character = Character.ReadBinary(binaryReader, out var id);
                        bitmapFont.Characters[id] = character;
                    }

                    break;
                }

                case BlockID.KerningPairs:
                {
                    var kerningBlockSize = binaryReader.ReadInt32();

                    if (kerningBlockSize % KerningPair.SizeInBytes != 0)
                    {
                        throw new InvalidDataException("Invalid kerning block size.");
                    }

                    var kerningCount = kerningBlockSize / KerningPair.SizeInBytes;

                    bitmapFont.KerningPairs = new Dictionary <KerningPair, int>(kerningCount);

                    for (var i = 0; i < kerningCount; i++)
                    {
                        var kerningPair = KerningPair.ReadBinary(binaryReader, out var amount);
                        if (bitmapFont.KerningPairs.ContainsKey(kerningPair))
                        {
                            continue;
                        }
                        bitmapFont.KerningPairs[kerningPair] = amount;
                    }

                    break;
                }

                default:
                {
                    throw new InvalidDataException("Invalid block ID.");
                }
                }
            }

            return(bitmapFont);
        }