public static bool BuildFont(Info fontInfo, tk2dFontData target, float scale, int charPadX, bool dupeCaps, bool flipTextureY, Texture2D gradientTexture, int gradientCount)
{
float texWidth = fontInfo.scaleW;
float texHeight = fontInfo.scaleH;
float lineHeight = fontInfo.lineHeight;
target.lineHeight = lineHeight * scale;
// Get number of characters (lastindex + 1)
int maxCharId = 0;
int maxUnicodeChar = 100000;
foreach (var theChar in fontInfo.chars)
{
if (theChar.id > maxUnicodeChar)
{
// in most cases the font contains unwanted characters!
Debug.LogError("Unicode character id exceeds allowed limit: " + theChar.id.ToString() + ". Skipping.");
continue;
}
if (theChar.id > maxCharId) maxCharId = theChar.id;
}
// decide to use dictionary if necessary
// 2048 is a conservative lower floor
bool useDictionary = maxCharId > 2048;
Dictionary<int, tk2dFontChar> charDict = (useDictionary)?new Dictionary<int, tk2dFontChar>():null;
tk2dFontChar[] chars = (useDictionary)?null:new tk2dFontChar[maxCharId + 1];
int minChar = 0x7fffffff;
int maxCharWithinBounds = 0;
int numLocalChars = 0;
float largestWidth = 0.0f;
foreach (var theChar in fontInfo.chars)
{
tk2dFontChar thisChar = new tk2dFontChar();
int id = theChar.id;
int x = theChar.x;
int y = theChar.y;
int width = theChar.width;
int height = theChar.height;
int xoffset = theChar.xoffset;
int yoffset = theChar.yoffset;
int xadvance = theChar.xadvance + charPadX;
// special case, if the width and height are zero, the origin doesn't need to be offset
// handles problematic case highlighted here:
// http://2dtoolkit.com/forum/index.php/topic,89.msg220.html
if (width == 0 && height == 0)
{
xoffset = 0;
yoffset = 0;
}
// precompute required data
float px = xoffset * scale;
float py = (lineHeight - yoffset) * scale;
if (theChar.texOverride)
{
int w = theChar.texW;
int h = theChar.texH;
if (theChar.texFlipped)
{
h = theChar.texW;
w = theChar.texH;
}
thisChar.p0 = new Vector3(px + theChar.texOffsetX * scale, py - theChar.texOffsetY * scale, 0);
thisChar.p1 = new Vector3(px + (theChar.texOffsetX + w) * scale, py - (theChar.texOffsetY + h) * scale, 0);
thisChar.uv0 = new Vector2((theChar.texX) / texWidth, (theChar.texY + theChar.texH) / texHeight);
thisChar.uv1 = new Vector2((theChar.texX + theChar.texW) / texWidth, (theChar.texY) / texHeight);
thisChar.flipped = theChar.texFlipped;
}
else
{
thisChar.p0 = new Vector3(px, py, 0);
thisChar.p1 = new Vector3(px + width * scale, py - height * scale, 0);
if (flipTextureY)
{
thisChar.uv0 = new Vector2(x / texWidth, y / texHeight);
thisChar.uv1 = new Vector2(thisChar.uv0.x + width / texWidth, thisChar.uv0.y + height / texHeight);
}
else
{
thisChar.uv0 = new Vector2(x / texWidth, 1.0f - y / texHeight);
thisChar.uv1 = new Vector2(thisChar.uv0.x + width / texWidth, thisChar.uv0.y - height / texHeight);
}
thisChar.flipped = false;
}
thisChar.advance = xadvance * scale;
largestWidth = Mathf.Max(thisChar.advance, largestWidth);
// Needs gradient data
if (gradientTexture != null)
{
// build it up assuming the first gradient
float x0 = (float)(0.0f / gradientCount);
float x1 = (float)(1.0f / gradientCount);
float y0 = 1.0f;
float y1 = 0.0f;
// align to glyph if necessary
thisChar.gradientUv = new Vector2[4];
thisChar.gradientUv[0] = new Vector2(x0, y0);
thisChar.gradientUv[1] = new Vector2(x1, y0);
thisChar.gradientUv[2] = new Vector2(x0, y1);
thisChar.gradientUv[3] = new Vector2(x1, y1);
}
if (id <= maxCharId)
{
maxCharWithinBounds = (id > maxCharWithinBounds) ? id : maxCharWithinBounds;
minChar = (id < minChar) ? id : minChar;
if (useDictionary)
charDict[id] = thisChar;
else
chars[id] = thisChar;
++numLocalChars;
}
}
// duplicate capitals to lower case, or vice versa depending on which ones exist
if (dupeCaps)
{
for (int uc = 'A'; uc <= 'Z'; ++uc)
{
int lc = uc + ('a' - 'A');
if (useDictionary)
{
if (charDict.ContainsKey(uc))
charDict[lc] = charDict[uc];
else if (charDict.ContainsKey(lc))
charDict[uc] = charDict[lc];
}
else
{
if (chars[lc] == null) chars[lc] = chars[uc];
else if (chars[uc] == null) chars[uc] = chars[lc];
}
}
}
// share null char, same pointer
var nullChar = new tk2dFontChar();
nullChar.gradientUv = new Vector2[4]; // this would be null otherwise
target.largestWidth = largestWidth;
if (useDictionary)
{
// guarantee at least the first 256 characters
for (int i = 0; i < 256; ++i)
{
if (!charDict.ContainsKey(i))
charDict[i] = nullChar;
}
target.chars = null;
target.SetDictionary(charDict);
target.useDictionary = true;
}
else
{
target.chars = new tk2dFontChar[maxCharId + 1];
for (int i = 0; i <= maxCharId; ++i)
{
target.chars[i] = chars[i];
if (target.chars[i] == null)
{
target.chars[i] = nullChar; // zero everything, null char
}
}
target.charDict = null;
target.useDictionary = false;
}
// kerning
target.kerning = new tk2dFontKerning[fontInfo.kernings.Count];
for (int i = 0; i < target.kerning.Length; ++i)
{
tk2dFontKerning kerning = new tk2dFontKerning();
kerning.c0 = fontInfo.kernings[i].first;
kerning.c1 = fontInfo.kernings[i].second;
kerning.amount = fontInfo.kernings[i].amount * scale;
target.kerning[i] = kerning;
}
return true;
}