forked from Zbyl/BFGFontTool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBMFonts.cs
220 lines (193 loc) · 8.88 KB
/
BMFonts.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
namespace BFGFontTool
{
/// <summary>
/// These are classes represent fonts generated by BMFont (http://www.angelcode.com/products/bmfont/).
/// Only loading plain text font descriptors is supported.
/// Those classes probably would be cleaner if we used XML font descriptor instead of the plain text one...
/// </summary>
public class BMGlyph
{
public int id; // char utf32
public int x; // x position in image (in pixels)
public int y; // y position in image (in pixels)
public int width; // width in image (in pixels)
public int height; // height in image (in pixels)
public int xoffset; // offset from pen position to start of glyph (in pixels)
public int yoffset; // offset from top of the line to start of glyph (in pixels)
public int xadvance; // how much to move pen after drawing glyph (in pixels)
public int page; // image number
public int chnl; // channel mask in the image (0xF == all channels) (important when chars are packed)
public bool Load(string glyphLine)
{
string pattern = @"char\s+id=(\d+)\s+x=(\d+)\s+y=(\d+)\s+width=(\d+)\s+height=(\d+)\s+xoffset=([+\-\d]+)\s+yoffset=([+\-\d]+)\s+xadvance=([+\-\d]+)\s+page=(\d+)\s+chnl=([+\-\d]+)";
var regex = new Regex(pattern);
var match = regex.Match(glyphLine);
if (!match.Success)
return false;
id = int.Parse(match.Groups[1].Value);
x = int.Parse(match.Groups[2].Value);
y = int.Parse(match.Groups[3].Value);
width = int.Parse(match.Groups[4].Value);
height = int.Parse(match.Groups[5].Value);
xoffset = int.Parse(match.Groups[6].Value);
yoffset = int.Parse(match.Groups[7].Value);
xadvance = int.Parse(match.Groups[8].Value);
page = int.Parse(match.Groups[9].Value);
chnl = int.Parse(match.Groups[10].Value);
return true;
}
}
public class BMPage
{
public int id;
public string file;
public bool Load(string line)
{
string pattern = @"page\s+id=(\d+)\s+file=""([^""]+)""";
var regex = new Regex(pattern);
var match = regex.Match(line);
if (!match.Success)
return false;
id = int.Parse(match.Groups[1].Value);
file = match.Groups[2].Value;
return true;
}
}
public class BMFont
{
public List<BMGlyph> glyphs = new List<BMGlyph>();
public List<BMPage> pages = new List<BMPage>();
// information about how the font was generated
// see http://www.angelcode.com/products/bmfont/doc/file_format.html
public string faceName;
public int size; // font size in points
public bool bold;
public bool italic;
public string charset;
public bool unicode; // true if unicode (charset is empty then)
public int heightStretchPercent;
public bool fontSmoothing;
public int antiAliasLevel;
public int paddingT;
public int paddingR;
public int paddingB;
public int paddingL;
public int spacingHoriz;
public int spacingVert;
public int outlineThickness;
public bool LoadInfo(string line)
{
string pattern = @"info\s+face=""([^""]*)""\s+size=([-+0-9]+)\s+bold=(\d)\s+italic=(\d)\s+charset=""([^""]*)""\s+unicode=(\d)\s+stretchH=(\d+)\s+smooth=(\d)\s+aa=(\d)\s+padding=(\d+),(\d+),(\d+),(\d+)\s+spacing=(\d+),(\d+)\s+outline=(\d+)";
var regex = new Regex(pattern);
var match = regex.Match(line);
if (!match.Success)
return false;
faceName = match.Groups[1].Value;
size = int.Parse(match.Groups[2].Value);
bold = int.Parse(match.Groups[3].Value) != 0;
italic = int.Parse(match.Groups[4].Value) != 0;
charset = match.Groups[5].Value;
unicode = int.Parse(match.Groups[6].Value) != 0;
heightStretchPercent = int.Parse(match.Groups[7].Value);
fontSmoothing = int.Parse(match.Groups[8].Value) != 0;
antiAliasLevel = int.Parse(match.Groups[9].Value);
paddingT = int.Parse(match.Groups[10].Value);
paddingR = int.Parse(match.Groups[11].Value);
paddingB = int.Parse(match.Groups[12].Value);
paddingL = int.Parse(match.Groups[13].Value);
spacingHoriz = int.Parse(match.Groups[14].Value);
spacingVert = int.Parse(match.Groups[15].Value);
outlineThickness = int.Parse(match.Groups[16].Value);
return true;
}
// information about the generated font
public int lineHeight; // line height
public int fontBase; // dist from top to baseline
public int scaleW; // width of the picture
public int scaleH; // height of the picture
public int numPages; // numeber of pictures
public bool packed; // true if glyphs are packed into multiple channels
public int alphaChnl; // contents of alpha channel: 0 - glyph, 1 - outline, 2 - encoded glyph & outline, 3 - zero, 4 - one
public int redChnl; // same
public int greenChnl; // same
public int blueChnl; // same
public bool LoadCommon(string line)
{
string pattern = @"common\s+lineHeight=(\d+)\s+base=([+\-\d]+)\s+scaleW=(\d+)\s+scaleH=(\d+)\s+pages=(\d+)\s+packed=(\d+)\s+alphaChnl=(\d+)\s+redChnl=(\d+)\s+greenChnl=(\d+)\s+blueChnl=(\d+)";
var regex = new Regex(pattern);
var match = regex.Match(line);
if (!match.Success)
return false;
lineHeight = int.Parse(match.Groups[1].Value);
fontBase = int.Parse(match.Groups[2].Value);
scaleW = int.Parse(match.Groups[3].Value);
scaleH = int.Parse(match.Groups[4].Value);
numPages = int.Parse(match.Groups[5].Value);
packed = int.Parse(match.Groups[6].Value) != 0;
alphaChnl = int.Parse(match.Groups[7].Value);
redChnl = int.Parse(match.Groups[8].Value);
greenChnl = int.Parse(match.Groups[9].Value);
blueChnl = int.Parse(match.Groups[10].Value);
return true;
}
public void Load(string fileName)
{
string[] allLines = File.ReadAllLines(fileName);
if (allLines.Count() < 2)
throw new ApplicationException("Invalid format!");
if (!LoadInfo(allLines[0]))
throw new ApplicationException("Invalid format!");
if (!LoadCommon(allLines[1]))
throw new ApplicationException("Invalid format!");
var glyphLines = from line in allLines
where line.StartsWith("char")
select line;
var pageLines = from line in allLines
where line.StartsWith("page")
select line;
foreach (string line in glyphLines)
{
BMGlyph glyph = new BMGlyph();
if (glyph.Load(line))
{
glyphs.Add(glyph);
}
}
foreach (string line in pageLines)
{
BMPage page = new BMPage();
if (page.Load(line))
{
pages.Add(page);
}
}
}
}
/// <summary>
/// This class is a helper class that defines additional icons that BMFont can insert into the font.
/// We can use this to merge a few fonts together.
/// This is also the way we convert Doom 3 fonts into BFG fonts:
/// 1. First decompose D3 font into "icons" and BMIconInfos,
/// 2. Then append those BMIconInfos to the BMFont's configuration file,
/// 3. Then use BMFont to generate the font using this configuration,
/// 4. Then convert resulting .fnt into BFG .dat font.
/// </summary>
public class BMIconInfo
{
public string imageFile;
public int charId; // UTF32
public int xoffset;
public int yoffset;
public int xadvance;
public override string ToString()
{
return string.Format("icon=\"{0}\",{1},{2},{3},{4}", imageFile, charId, xoffset, yoffset, xadvance);
}
}
}