171 lines
5.7 KiB
C#
171 lines
5.7 KiB
C#
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
|
||
|
||
/// <summary>
|
||
/// Loads a bitmap font from an XML file.
|
||
/// </summary>
|
||
public static BitmapFont LoadFontFromXmlFile(Stream stream)
|
||
{
|
||
var document = new XmlDocument();
|
||
IDictionary<int, Page> pageData = new SortedDictionary<int, Page>();
|
||
IDictionary<Kerning, int> kerningDictionary = new Dictionary<Kerning, int>();
|
||
IDictionary<char, Character> charDictionary = new Dictionary<char, Character>();
|
||
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
|
||
|
||
/// <summary>
|
||
/// Creates a Padding object from a string representation
|
||
/// </summary>
|
||
/// <param name="s">The string.</param>
|
||
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())
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// Creates a Point object from a string representation
|
||
/// </summary>
|
||
/// <param name="s">The string.</param>
|
||
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())
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// Converts the given collection into an array
|
||
/// </summary>
|
||
/// <typeparam name="T">Type of the items in the array</typeparam>
|
||
/// <param name="values">The values.</param>
|
||
private static T[] ToArray<T>(ICollection<T> 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
|
||
}
|
||
}
|