using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Xml; // public domain assumed from cyotek.com namespace Cyotek.Drawing.BitmapFont { // Parsing class for bitmap fonts generated by AngelCode BMFont // http://www.angelcode.com/products/bmfont/ public static class BitmapFontLoader { #region  Public Class Methods /// /// Loads a bitmap font from an XML file. /// public static BitmapFont LoadFontFromXmlFile(Stream stream) { var document = new XmlDocument(); IDictionary pageData = new SortedDictionary(); IDictionary kerningDictionary = new Dictionary(); IDictionary charDictionary = new Dictionary(); var font = new BitmapFont(); document.Load(stream); XmlNode root = document.DocumentElement; // load the basic attributes var properties = root.SelectSingleNode("info"); font.FamilyName = properties.Attributes["face"].Value; font.FontSize = Convert.ToInt32(properties.Attributes["size"].Value); font.Bold = Convert.ToInt32(properties.Attributes["bold"].Value) != 0; font.Italic = Convert.ToInt32(properties.Attributes["italic"].Value) != 0; font.Unicode = Convert.ToInt32(properties.Attributes["unicode"].Value) != 0; font.StretchedHeight = Convert.ToInt32(properties.Attributes["stretchH"].Value); font.Charset = properties.Attributes["charset"].Value; font.Smoothed = Convert.ToInt32(properties.Attributes["smooth"].Value) != 0; font.SuperSampling = Convert.ToInt32(properties.Attributes["aa"].Value); font.Padding = ParsePadding(properties.Attributes["padding"].Value); font.Spacing = ParsePoint(properties.Attributes["spacing"].Value); font.OutlineSize = Convert.ToInt32(properties.Attributes["outline"].Value); // common attributes properties = root.SelectSingleNode("common"); font.BaseHeight = Convert.ToInt32(properties.Attributes["lineHeight"].Value); font.LineHeight = Convert.ToInt32(properties.Attributes["base"].Value); font.TextureSize = new Size ( Convert.ToInt32(properties.Attributes["scaleW"].Value), Convert.ToInt32(properties.Attributes["scaleH"].Value) ); font.Packed = Convert.ToInt32(properties.Attributes["packed"].Value) != 0; font.AlphaChannel = Convert.ToInt32(properties.Attributes["alphaChnl"].Value); font.RedChannel = Convert.ToInt32(properties.Attributes["redChnl"].Value); font.GreenChannel = Convert.ToInt32(properties.Attributes["greenChnl"].Value); font.BlueChannel = Convert.ToInt32(properties.Attributes["blueChnl"].Value); // load texture information foreach (XmlNode node in root.SelectNodes("pages/page")) { var page = new Page { Id = Convert.ToInt32(node.Attributes["id"].Value), FileName = node.Attributes["file"].Value }; pageData.Add(page.Id, page); } font.Pages = ToArray(pageData.Values); // load character information foreach (XmlNode node in root.SelectNodes("chars/char")) { var character = new Character { Char = (char) Convert.ToInt32(node.Attributes["id"].Value), Bounds = new Rectangle ( Convert.ToInt32(node.Attributes["x"].Value), Convert.ToInt32(node.Attributes["y"].Value), Convert.ToInt32(node.Attributes["width"].Value), Convert.ToInt32(node.Attributes["height"].Value) ), Offset = new Point ( Convert.ToInt32(node.Attributes["xoffset"].Value), Convert.ToInt32(node.Attributes["yoffset"].Value) ), XAdvance = Convert.ToInt32(node.Attributes["xadvance"].Value), TexturePage = Convert.ToInt32(node.Attributes["page"].Value), Channel = Convert.ToInt32(node.Attributes["chnl"].Value) }; charDictionary.Add(character.Char, character); } font.Characters = charDictionary; // loading kerning information foreach (XmlNode node in root.SelectNodes("kernings/kerning")) { var key = new Kerning((char)Convert.ToInt32(node.Attributes["first"].Value), (char)Convert.ToInt32(node.Attributes["second"].Value), Convert.ToInt32(node.Attributes["amount"].Value)); if (!kerningDictionary.ContainsKey(key)) { kerningDictionary.Add(key, key.Amount); } } font.Kernings = kerningDictionary; return font; } #endregion  Public Class Methods #region  Private Class Methods /// /// Creates a Padding object from a string representation /// /// The string. private static Padding ParsePadding(string s) { var parts = s.Split(','); return new Padding { Left = Convert.ToInt32(parts[3].Trim()), Top = Convert.ToInt32(parts[0].Trim()), Right = Convert.ToInt32(parts[1].Trim()), Bottom = Convert.ToInt32(parts[2].Trim()) }; } /// /// Creates a Point object from a string representation /// /// The string. private static Point ParsePoint(string s) { var parts = s.Split(','); return new Point { X = Convert.ToInt32(parts[0].Trim()), Y = Convert.ToInt32(parts[1].Trim()) }; } /// /// Converts the given collection into an array /// /// Type of the items in the array /// The values. private static T[] ToArray(ICollection values) { // avoid a forced .NET 3 dependency just for one call to Linq var result = new T[values.Count]; values.CopyTo(result, 0); return result; } #endregion  Private Class Methods } }