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; }
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://unikronsoftware.com/2dtoolkit/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); }