// Methods public tk2dFontData GetReplacementData() { int num = 1; ControlPromptDisplayHelpers.ControllerMapSpriteType mapSpriteType = ControlPromptDisplayHelpers.GetMapSpriteType(); if (this.m_hasCached && ((this.m_lastLanguageFlag != num) || (mapSpriteType != this.m_lastControllerType))) { this.m_hasCached = false; } if (!this.m_hasCached) { this.m_cached = this.m_baseFont; foreach (FontTextureReplacement replacement in this.m_replacements) { if ((replacement.GetLanguageFlag() & num) != 0) { this.m_cached = replacement.GetFont(mapSpriteType); replacement.SetControllerTexture(this.m_cached, mapSpriteType); } } this.m_hasCached = true; this.m_lastLanguageFlag = num; this.m_lastControllerType = mapSpriteType; } return(this.m_cached); }
void InitInstance() { if (_fontInst == null && data.font != null) { _fontInst = data.font.inst; } }
// Use this to get a correctly set up textgeomdata object // This uses a static global tmpData object and is not thread safe // Fortunately for us, neither is the rest of Unity. public static GeomData Data(tk2dTextMeshData textMeshData, tk2dFontData fontData, string formattedText) { tmpData.textMeshData = textMeshData; tmpData.fontInst = fontData; tmpData.formattedText = formattedText; return(tmpData); }
static float GetXAnchorForWidth(float lineWidth, GeomData geomData) { tk2dTextMeshData data = geomData.textMeshData; tk2dFontData _fontInst = geomData.fontInst; int widthAnchor = (int)data.anchor % 3; switch (widthAnchor) { case 0: return(0.0f); // left case 1: // center { float x = -lineWidth / 2.0f; if (_fontInst.version >= 2) { float tx = _fontInst.texelSize.x * data.scale.x; return(Mathf.Floor(x / tx) * tx); } return(x); } case 2: return(-lineWidth); // right } return(0.0f); }
static float GetYAnchorForHeight(float textHeight, GeomData geomData) { tk2dTextMeshData data = geomData.textMeshData; tk2dFontData _fontInst = geomData.fontInst; int heightAnchor = (int)data.anchor / 3; float lineHeight = (_fontInst.lineHeight + data.lineSpacing) * data.scale.y; switch (heightAnchor) { case 0: return(-lineHeight); case 1: { float y = -textHeight / 2.0f - lineHeight; if (_fontInst.version >= 2) { float ty = _fontInst.texelSize.y * data.scale.y; return(Mathf.Floor(y / ty) * ty); } else { return(y); } } case 2: return(-textHeight - lineHeight); } return(-lineHeight); }
// Use this to get a correctly set up textCurvedGeomData object // This uses a static global tmpData object and is not thread safe // Fortunately for us, neither is the rest of Unity. public static CurvedGeomData Data(tk2dCurvedTextMeshData textMeshData, tk2dFontData fontData, string formattedText) { tmpData.textMeshData = textMeshData; tmpData.fontInst = fontData; tmpData.formattedText = formattedText; return tmpData; }
void InitInstance() { if (_fontInst == null && _font != null) { _fontInst = _font.inst; } }
void InitInstance() { if (data != null && data.font != null) { _fontInst = data.font.inst; _fontInst.InitDictionary(); } }
// Use this for initialization void Awake() { if (font != null) { defaultFontData = font; } RebuildAll(); }
public void ForceBuild() { if (data.font != null) { _fontInst = data.font.inst; UpdateMaterial(); } Init(true); }
public void ResetPlatformData() { if (hasPlatformData && platformSpecificData) { platformSpecificData = null; } materialInst = null; }
public void ResetPlatformData() { if (hasPlatformData && platformSpecificData) { // Sprite collection unloads its own data platformSpecificData = null; } materialInst = null; }
public void CopyFrom(tk2dSpriteCollectionFont src) { active = src.active; bmFont = src.bmFont; texture = src.texture; dupeCaps = src.dupeCaps; flipTextureY = src.flipTextureY; charPadX = src.charPadX; data = src.data; editorData = src.editorData; }
static void AddFontFromIndex(tk2dGenericIndexItem indexEntry) { string path = AssetDatabase.GUIDToAssetPath(indexEntry.dataGUID); tk2dFontData data = AssetDatabase.LoadAssetAtPath(path, typeof(tk2dFontData)) as tk2dFontData; if (data == null) { CustomDebug.LogError(string.Format("Unable to load font data '{0}' at path '{1}'", indexEntry.AssetName, path)); return; } MakeLoadableAsset(data, ""); // can't make it directly loadable, hence no asset name data = null; }
bool ParseBMFont(string path, tk2dFontData fontData, tk2dFont source) { float scale = 2.0f * source.sizeDef.OrthoSize / source.sizeDef.TargetHeight; tk2dEditor.Font.Info fontInfo = tk2dEditor.Font.Builder.ParseBMFont(path); if (fontInfo != null) { return(tk2dEditor.Font.Builder.BuildFont(fontInfo, fontData, scale, source.charPadX, source.dupeCaps, source.flipTextureY, source.gradientTexture, source.gradientCount)); } else { return(false); } }
public void SetControllerTexture(tk2dFontData font, ControlPromptDisplayHelpers.ControllerMapSpriteType cType) { foreach (FontGroup.ControllerTypeReplacement replacement in this.m_replacement) { if (replacement.m_spriteType == cType) { if (replacement.m_replacementTexture != null) { font.materialInst.mainTexture = replacement.m_replacementTexture; } break; } } }
public void CopyFrom(tk2dSpriteCollectionFont src) { this.active = src.active; this.bmFont = src.bmFont; this.texture = src.texture; this.dupeCaps = src.dupeCaps; this.flipTextureY = src.flipTextureY; this.charPadX = src.charPadX; this.data = src.data; this.editorData = src.editorData; this.materialId = src.materialId; this.gradientCount = src.gradientCount; this.gradientTexture = src.gradientTexture; this.useGradient = src.useGradient; }
public void CopyFrom(tk2dSpriteCollectionFont src) { active = src.active; bmFont = src.bmFont; texture = src.texture; dupeCaps = src.dupeCaps; flipTextureY = src.flipTextureY; charPadX = src.charPadX; data = src.data; editorData = src.editorData; materialId = src.materialId; gradientCount = src.gradientCount; gradientTexture = src.gradientTexture; useGradient = src.useGradient; }
public void CopyFrom(tk2dSpriteCollectionFont src) { active = src.active; bmFont = src.bmFont; texture = src.texture; dupeCaps = src.dupeCaps; flipTextureY = src.flipTextureY; charPadX = src.charPadX; data = src.data; editorData = src.editorData; materialId = src.materialId; gradientCount = src.gradientCount; gradientTexture = src.gradientTexture; useGradient = src.useGradient; }
private void Awake() { this.UpgradeData(); if (this.data.font != null) { this._fontInst = this.data.font.inst; } this.updateFlags = UpdateFlags.UpdateBuffers; if (this.data.font != null) { this.Init(); this.UpdateMaterial(); } this.updateFlags = UpdateFlags.UpdateNone; }
static void DoCreateTextMesh() { tk2dFontData fontData = null; // Find reference in scene tk2dTextMesh dupeMesh = GameObject.FindObjectOfType(typeof(tk2dTextMesh)) as tk2dTextMesh; if (dupeMesh) { fontData = dupeMesh.font; } // Find in library if (fontData == null) { tk2dGenericIndexItem[] allFontEntries = tk2dEditorUtility.GetOrCreateIndex().GetFonts(); foreach (var v in allFontEntries) { if (v.managed) { continue; } tk2dFontData data = v.GetData <tk2dFontData>(); if (data != null) { fontData = data; break; } } } if (fontData == null) { EditorUtility.DisplayDialog("Create TextMesh", "Unable to create text mesh as no Fonts have been found.", "Ok"); return; } GameObject go = tk2dEditorUtility.CreateGameObjectInScene("TextMesh"); tk2dTextMesh textMesh = go.AddComponent <tk2dTextMesh>(); textMesh.font = fontData; textMesh.text = "New TextMesh"; textMesh.Commit(); Selection.activeGameObject = go; Undo.RegisterCreatedObjectUndo(go, "Create TextMesh"); }
// Methods public tk2dFontData GetFont(ControlPromptDisplayHelpers.ControllerMapSpriteType cType) { tk2dFontData font = this.m_font; foreach (FontGroup.ControllerTypeReplacement replacement in this.m_replacement) { if (replacement.m_spriteType == cType) { if (replacement.m_font != null) { font = replacement.m_font; } return(font); } } return(font); }
public FontMeshData(string name, string fontBitmapPath, string fontInfoPath) { GameObject obj = new GameObject(); obj.name = String.Format("DataFontMesh{0}", name); this.data = obj.AddComponent<tk2dFontData>(); FontInfo fontInfo = FontBuilder.ParseBMFont(fontInfoPath); FontBuilder.BuildFont(fontInfo, data, 1, 0, false, false, null, 0); Material fontMaterial = new Material(Shader.Find("tk2d/BlendVertexColor")); Texture2D texture = SpriteLoader.LoadTexture(fontBitmapPath, false); fontMaterial.mainTexture = texture; this.data.material = fontMaterial; this.width = this.data.largestWidth; this.height = this.data.lineHeight; }
static void DoCreateTextMesh() { tk2dFontData fontData = null; Material material = null; // Find reference in scene tk2dTextMesh dupeMesh = GameObject.FindObjectOfType(typeof(tk2dTextMesh)) as tk2dTextMesh; if (dupeMesh) { fontData = dupeMesh.font; material = dupeMesh.GetComponent <MeshRenderer>().sharedMaterial; } // Find in library if (fontData == null) { tk2dFont[] allFontData = tk2dEditorUtility.GetOrCreateIndex().GetFonts(); foreach (var v in allFontData) { if (v.data != null) { fontData = v.data; material = fontData.material; } } } if (fontData == null) { EditorUtility.DisplayDialog("Create TextMesh", "Unable to create text mesh as no Fonts have been found.", "Ok"); return; } GameObject go = tk2dEditorUtility.CreateGameObjectInScene("TextMesh"); tk2dTextMesh textMesh = go.AddComponent <tk2dTextMesh>(); textMesh.font = fontData; textMesh.text = "New TextMesh"; textMesh.Commit(); textMesh.GetComponent <MeshRenderer>().material = material; Selection.activeGameObject = go; Undo.RegisterCreatedObjectUndo(go, "Create TextMesh"); }
// Use this for initialization void Awake() { UpgradeData(); if (data.font != null) { _fontInst = data.font.inst; } // force rebuild when awakened, for when the object has been pooled, etc // this is probably not the best way to do it updateFlags = UpdateFlags.UpdateBuffers; if (data.font != null) { Init(); UpdateMaterial(); } }
/// <summary> /// Calculates the mesh dimensions for the given string /// and returns a width and height. /// </summary> public static Vector2 GetMeshDimensionsForString(this tk2dTextMeshData geomData, tk2dColoredText inputText, int startIdx, int count) { tk2dTextMeshData data = geomData; tk2dFontData _fontInst = data.FontInst; float maxWidth = 0.0f; float cursorX = 0.0f; float cursorY = 0.0f; for (int i = startIdx; (i < inputText.Length) && (i < (startIdx + count)); ++i) { int idx = inputText[i]; if (idx == '\n') { maxWidth = Mathf.Max(cursorX, maxWidth); cursorX = 0.0f; cursorY -= data.ActualLineSpaceHeight; } else { // Get the character from dictionary / array tk2dFontChar chr = _fontInst.GetCharForIndex(idx, 0); cursorX += (chr.advance + data.Spacing) * data.TotalScale.x; if (data.kerning && i < inputText.Length - 1) { foreach (var k in _fontInst.kerning) { if (k.c0 == inputText[i] && k.c1 == inputText[i + 1]) { cursorX += k.amount * data.TotalScale.x; break; } } } } } maxWidth = Mathf.Max(cursorX, maxWidth); cursorY -= data.ActualLineHeight; return(new Vector2(maxWidth, cursorY)); }
public FontMeshData(string name, string fontBitmapPath, string fontInfoPath) { GameObject obj = new GameObject(); obj.name = String.Format("DataFontMesh{0}", name); this.data = obj.AddComponent <tk2dFontData>(); FontInfo fontInfo = FontBuilder.ParseBMFont(fontInfoPath); FontBuilder.BuildFont(fontInfo, data, 1, 0, false, false, null, 0); Material fontMaterial = new Material(Shader.Find("tk2d/BlendVertexColor")); Texture2D texture = SpriteLoader.LoadTexture(fontBitmapPath, false); fontMaterial.mainTexture = texture; this.data.material = fontMaterial; this.width = this.data.largestWidth; this.height = this.data.lineHeight; }
// Use this for initialization void Awake() { UpgradeData(); if (data.font != null) _fontInst = data.font.inst; // force rebuild when awakened, for when the object has been pooled, etc // this is probably not the best way to do it updateFlags = UpdateFlags.UpdateBuffers; if (data.font != null) { Init(); UpdateMaterial(); } // Sensibly reset, so tk2dUpdateManager can deal with this properly updateFlags = UpdateFlags.UpdateNone; }
// Use this for initialization void Awake() { if (_font != null) { _fontInst = _font.inst; } if (pixelPerfect) { MakePixelPerfect(); } // force rebuild when awakened, for when the object has been pooled, etc // this is probably not the best way to do it updateFlags = UpdateFlags.UpdateBuffers; if (_font != null) { Init(); UpdateMaterial(); } }
public static float GetYAnchorForHeight(this tk2dTextMeshData geomData, float textHeight) { tk2dTextMeshData data = geomData; tk2dFontData _fontInst = data.FontInst; float lineHeight = data.ActualLineHeight; switch (data.anchor) { case TextAnchor.UpperCenter: case TextAnchor.UpperLeft: case TextAnchor.UpperRight: return(-lineHeight); case TextAnchor.MiddleCenter: case TextAnchor.MiddleLeft: case TextAnchor.MiddleRight: { float y = -textHeight / 2.0f - lineHeight; if (_fontInst.version >= 2) { float ty = _fontInst.texelSize.y * data.TotalScale.y; return(Mathf.Floor(y / ty) * ty); } else { return(y); } } case TextAnchor.LowerCenter: case TextAnchor.LowerLeft: case TextAnchor.LowerRight: return(-textHeight - lineHeight); } return(-lineHeight); }
// Use this for initialization void Awake() { if (_font != null) _fontInst = _font.inst; if (pixelPerfect) MakePixelPerfect(); // force rebuild when awakened, for when the object has been pooled, etc // this is probably not the best way to do it updateFlags = UpdateFlags.UpdateBuffers; if (_font != null) { Init(); UpdateMaterial(); } }
void InitInstance() { if (data != null && data.font != null) { _fontInst = data.font.inst; _fontInst.InitDictionary(); } }
public void ForceBuild() { if (this.data.font != null) { this._fontInst = this.data.font.inst; this.UpdateMaterial(); } this.Init(true); }
private void InitInstance() { if ((this.data != null) && (this.data.font != null)) { this._fontInst = this.data.font.inst; this._fontInst.InitDictionary(); } }
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; }
// Use this for initialization void Awake() { UpgradeData(); if (data.font != null) _fontInst = data.font.inst; // force rebuild when awakened, for when the object has been pooled, etc // this is probably not the best way to do it updateFlags = UpdateFlags.UpdateBuffers; if (data.font != null) { Init(); UpdateMaterial(); } // Sensibly reset, so tk2dUpdateManager can deal with this properly updateFlags = UpdateFlags.UpdateNone; }
public void ForceBuild() { if (_font != null) { _fontInst = _font; UpdateMaterial(); } Init(true); }
bool ParseBMFont(string path, tk2dFontData bmFont, tk2dFont source) { IntFontInfo fontInfo = null; try { XmlDocument doc = new XmlDocument(); doc.Load(path); fontInfo = ParseBMFontXml(doc); } catch { fontInfo = ParseBMFontText(path); } if (fontInfo == null || fontInfo.chars.Count == 0) return false; float texWidth = fontInfo.scaleW; float texHeight = fontInfo.scaleH; float lineHeight = fontInfo.lineHeight; float scale = 2.0f * source.targetOrthoSize / source.targetHeight; bmFont.lineHeight = lineHeight * scale; // Get largest index int numCharacters = 0; foreach (var theChar in fontInfo.chars) { if (theChar.id > numCharacters) numCharacters = theChar.id; } tk2dFontChar[] chars = new tk2dFontChar[numCharacters]; int minChar = 65536; 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 + source.charPadX; // precompute required data float px = xoffset * scale; float py = (lineHeight - yoffset) * scale; thisChar.p0 = new Vector3(px, py, 0); thisChar.p1 = new Vector3(px + width * scale, py - height * scale, 0); if (source.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.advance = xadvance * scale; largestWidth = Mathf.Max(thisChar.advance, largestWidth); // Needs gradient data if (source.gradientTexture != null) { // build it up assuming the first gradient float x0 = (float)(0.0f / source.gradientCount); float x1 = (float)(1.0f / source.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 < numCharacters) { maxCharWithinBounds = (id > maxCharWithinBounds) ? id : maxCharWithinBounds; minChar = (id < minChar) ? id : minChar; chars[id] = thisChar; ++numLocalChars; } } if (source.dupeCaps) { for (int uc = 'A'; uc <= 'Z'; ++uc) { int lc = uc + ('a' - 'A'); 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(); bmFont.largestWidth = largestWidth; bmFont.chars = new tk2dFontChar[numCharacters]; for (int i = 0; i < numCharacters; ++i) { bmFont.chars[i] = chars[i]; if (bmFont.chars[i] == null) { bmFont.chars[i] = nullChar; // zero everything, null char } } // kerning bmFont.kerning = new tk2dFontKerning[fontInfo.kernings.Count]; for (int i = 0; i < bmFont.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; bmFont.kerning[i] = kerning; } return true; }
public void ResetPlatformData() { if (this.hasPlatformData && (this.platformSpecificData != null)) { this.platformSpecificData = null; } this.materialInst = null; }
public void ResetPlatformData() { if (hasPlatformData && platformSpecificData) { // Sprite collection unloads its own data platformSpecificData = null; } materialInst = null; }
void InitInstance() { if (_fontInst == null && _font != null) _fontInst = _font.inst; }
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); }
bool ParseBMFont(string path, tk2dFontData bmFont, tk2dFont source) { IntFontInfo fontInfo = null; try { XmlDocument doc = new XmlDocument(); doc.Load(path); fontInfo = ParseBMFontXml(doc); } catch { fontInfo = ParseBMFontText(path); } if (fontInfo == null || fontInfo.chars.Count == 0) { return(false); } float texWidth = fontInfo.scaleW; float texHeight = fontInfo.scaleH; float lineHeight = fontInfo.lineHeight; float scale = 2.0f * source.targetOrthoSize / source.targetHeight; bmFont.lineHeight = lineHeight * scale; tk2dFontChar[] chars = new tk2dFontChar[source.numCharacters]; int minChar = 65536; 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; // precompute required data float px = xoffset * scale; float py = (lineHeight - yoffset) * scale; thisChar.p0 = new Vector3(px, py, 0); thisChar.p1 = new Vector3(px + width * scale, py - height * scale, 0); if (source.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.advance = xadvance * scale; largestWidth = Mathf.Max(thisChar.advance, largestWidth); // Needs gradient data if (source.gradientTexture != null) { // build it up assuming the first gradient float x0 = (float)(0.0f / source.gradientCount); float x1 = (float)(1.0f / source.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 < source.numCharacters) { maxCharWithinBounds = (id > maxCharWithinBounds) ? id : maxCharWithinBounds; minChar = (id < minChar) ? id : minChar; chars[id] = thisChar; ++numLocalChars; } } if (source.dupeCaps) { for (int uc = 'A'; uc <= 'Z'; ++uc) { int lc = uc + ('a' - 'A'); if (chars[lc] == null) { chars[lc] = chars[uc]; } else if (chars[uc] == null) { chars[uc] = chars[lc]; } } } bmFont.largestWidth = largestWidth; bmFont.chars = new tk2dFontChar[source.numCharacters]; for (int i = 0; i < source.numCharacters; ++i) { bmFont.chars[i] = chars[i]; if (bmFont.chars[i] == null) { bmFont.chars[i] = new tk2dFontChar(); // zero everything, null char } } // kerning bmFont.kerning = new tk2dFontKerning[fontInfo.kernings.Count]; for (int i = 0; i < bmFont.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; bmFont.kerning[i] = kerning; } return(true); }
// Use this for initialization void Awake() { UpgradeData(); if (data.font != null) _fontInst = data.font.inst; // force rebuild when awakened, for when the object has been pooled, etc // this is probably not the best way to do it updateFlags = UpdateFlags.UpdateBuffers; if (data.font != null) { Init(); UpdateMaterial(); } }
bool ParseBMFont(string path, tk2dFontData fontData, tk2dFont source) { float scale = 2.0f * source.sizeDef.OrthoSize / source.sizeDef.TargetHeight; tk2dEditor.Font.Info fontInfo = tk2dEditor.Font.Builder.ParseBMFont(path); if (fontInfo != null) return tk2dEditor.Font.Builder.BuildFont(fontInfo, fontData, scale, source.charPadX, source.dupeCaps, source.flipTextureY, source.gradientTexture, source.gradientCount); else return false; }
public void ResetPlatformData() { if (hasPlatformData && platformSpecificData) { platformSpecificData = null; } materialInst = null; }
// Draws the word wrap GUI void DrawWordWrapSceneGUI(tk2dTextMesh textMesh) { tk2dFontData font = textMesh.font; Transform transform = textMesh.transform; int px = textMesh.wordWrapWidth; Vector3 p0 = transform.position; float width = font.texelSize.x * px * transform.localScale.x; bool drawRightHandle = true; bool drawLeftHandle = false; switch (textMesh.anchor) { case TextAnchor.LowerCenter: case TextAnchor.MiddleCenter: case TextAnchor.UpperCenter: drawLeftHandle = true; p0 -= width * 0.5f * transform.right; break; case TextAnchor.LowerRight: case TextAnchor.MiddleRight: case TextAnchor.UpperRight: drawLeftHandle = true; drawRightHandle = false; p0 -= width * transform.right; break; } Vector3 p1 = p0 + width * transform.right; Handles.color = new Color32(255, 255, 255, 24); float subPin = font.texelSize.y * 2048; Handles.DrawLine(p0, p1); Handles.DrawLine(p0 - subPin * transform.up, p0 + subPin * transform.up); Handles.DrawLine(p1 - subPin * transform.up, p1 + subPin * transform.up); Handles.color = Color.white; Vector3 pin = transform.up * font.texelSize.y * 10.0f; Handles.DrawLine(p0 - pin, p0 + pin); Handles.DrawLine(p1 - pin, p1 + pin); if (drawRightHandle) { Vector3 newp1 = Handles.Slider(p1, transform.right, HandleUtility.GetHandleSize(p1), Handles.ArrowCap, 0.0f); if (newp1 != p1) { tk2dUndo.RecordObject(textMesh, "TextMesh Wrap Length"); int newPx = (int)Mathf.Round((newp1 - p0).magnitude / (font.texelSize.x * transform.localScale.x)); newPx = Mathf.Max(newPx, 0); textMesh.wordWrapWidth = newPx; textMesh.Commit(); } } if (drawLeftHandle) { Vector3 newp0 = Handles.Slider(p0, -transform.right, HandleUtility.GetHandleSize(p0), Handles.ArrowCap, 0.0f); if (newp0 != p0) { tk2dUndo.RecordObject(textMesh, "TextMesh Wrap Length"); int newPx = (int)Mathf.Round((p1 - newp0).magnitude / (font.texelSize.x * transform.localScale.x)); newPx = Mathf.Max(newPx, 0); textMesh.wordWrapWidth = newPx; textMesh.Commit(); } } }
/// <summary> /// Calculates the mesh dimensions for the given string /// and returns a width and height. /// </summary> public static Vector2 GetMeshDimensionsForString(string str, GeomData geomData) { tk2dTextMeshData data = geomData.textMeshData; tk2dFontData _fontInst = geomData.fontInst; float maxWidth = 0.0f; float cursorX = 0.0f; float cursorY = 0.0f; bool ignoreNextCharacter = false; int target = 0; for (int i = 0; i < str.Length && target < data.maxChars; ++i) { if (ignoreNextCharacter) { ignoreNextCharacter = false; continue; } int idx = str[i]; if (idx == '\n') { maxWidth = Mathf.Max(cursorX, maxWidth); cursorX = 0.0f; cursorY -= (_fontInst.lineHeight + data.lineSpacing) * data.scale.y; continue; } else if (data.inlineStyling) { if (idx == '^' && i + 1 < str.Length) { if (str[i + 1] == '^') { ignoreNextCharacter = true; } else { int cmdLength = 0; switch (str[i + 1]) { case 'c': cmdLength = 5; break; case 'C': cmdLength = 9; break; case 'g': cmdLength = 9; break; case 'G': cmdLength = 17; break; } i += cmdLength; continue; } } } bool inlineHatChar = (idx == '^'); // Get the character from dictionary / array tk2dFontChar chr; if (_fontInst.useDictionary) { if (!_fontInst.charDict.ContainsKey(idx)) { idx = 0; } chr = _fontInst.charDict[idx]; } else { if (idx >= _fontInst.chars.Length) { idx = 0; // should be space } chr = _fontInst.chars[idx]; } if (inlineHatChar) { idx = '^'; } cursorX += (chr.advance + data.spacing) * data.scale.x; if (data.kerning && i < str.Length - 1) { foreach (var k in _fontInst.kerning) { if (k.c0 == str[i] && k.c1 == str[i + 1]) { cursorX += k.amount * data.scale.x; break; } } } ++target; } maxWidth = Mathf.Max(cursorX, maxWidth); cursorY -= (_fontInst.lineHeight + data.lineSpacing) * data.scale.y; return(new Vector2(maxWidth, cursorY)); }
void InitInstance() { if (_fontInst == null && data.font != null) _fontInst = data.font.inst; }
public static int SetTextMeshGeom(Vector3[] pos, Vector2[] uv, Vector2[] uv2, Color32[] color, int offset, GeomData geomData) { tk2dTextMeshData data = geomData.textMeshData; tk2dFontData fontInst = geomData.fontInst; string formattedText = geomData.formattedText; meshTopColor = new Color32(255, 255, 255, 255); meshBottomColor = new Color32(255, 255, 255, 255); meshGradientTexU = (float)data.textureGradient / (float)((fontInst.gradientCount > 0) ? fontInst.gradientCount : 1); curGradientCount = fontInst.gradientCount; Vector2 dims = GetMeshDimensionsForString(geomData.formattedText, geomData); float offsetY = GetYAnchorForHeight(dims.y, geomData); float cursorX = 0.0f; float cursorY = 0.0f; int target = 0; int alignStartTarget = 0; for (int i = 0; i < formattedText.Length && target < data.maxChars; ++i) { int idx = formattedText[i]; tk2dFontChar chr; bool inlineHatChar = (idx == '^'); if (fontInst.useDictionary) { if (!fontInst.charDict.ContainsKey(idx)) { idx = 0; } chr = fontInst.charDict[idx]; } else { if (idx >= fontInst.chars.Length) { idx = 0; // should be space } chr = fontInst.chars[idx]; } if (inlineHatChar) { idx = '^'; } if (idx == '\n') { float lineWidth = cursorX; int alignEndTarget = target; // this is one after the last filled character if (alignStartTarget != target) { float xOffset = GetXAnchorForWidth(lineWidth, geomData); PostAlignTextData(pos, offset, alignStartTarget, alignEndTarget, xOffset); } alignStartTarget = target; cursorX = 0.0f; cursorY -= (fontInst.lineHeight + data.lineSpacing) * data.scale.y; continue; } else if (data.inlineStyling) { if (idx == '^') { if (i + 1 < formattedText.Length && formattedText[i + 1] == '^') { ++i; } else { i += HandleStyleCommand(formattedText.Substring(i + 1)); continue; } } } pos[offset + target * 4 + 0] = new Vector3(cursorX + chr.p0.x * data.scale.x, offsetY + cursorY + chr.p0.y * data.scale.y, 0); pos[offset + target * 4 + 1] = new Vector3(cursorX + chr.p1.x * data.scale.x, offsetY + cursorY + chr.p0.y * data.scale.y, 0); pos[offset + target * 4 + 2] = new Vector3(cursorX + chr.p0.x * data.scale.x, offsetY + cursorY + chr.p1.y * data.scale.y, 0); pos[offset + target * 4 + 3] = new Vector3(cursorX + chr.p1.x * data.scale.x, offsetY + cursorY + chr.p1.y * data.scale.y, 0); if (chr.flipped) { uv[offset + target * 4 + 0] = new Vector2(chr.uv1.x, chr.uv1.y); uv[offset + target * 4 + 1] = new Vector2(chr.uv1.x, chr.uv0.y); uv[offset + target * 4 + 2] = new Vector2(chr.uv0.x, chr.uv1.y); uv[offset + target * 4 + 3] = new Vector2(chr.uv0.x, chr.uv0.y); } else { uv[offset + target * 4 + 0] = new Vector2(chr.uv0.x, chr.uv0.y); uv[offset + target * 4 + 1] = new Vector2(chr.uv1.x, chr.uv0.y); uv[offset + target * 4 + 2] = new Vector2(chr.uv0.x, chr.uv1.y); uv[offset + target * 4 + 3] = new Vector2(chr.uv1.x, chr.uv1.y); } if (fontInst.textureGradients) { uv2[offset + target * 4 + 0] = chr.gradientUv[0] + new Vector2(meshGradientTexU, 0); uv2[offset + target * 4 + 1] = chr.gradientUv[1] + new Vector2(meshGradientTexU, 0); uv2[offset + target * 4 + 2] = chr.gradientUv[2] + new Vector2(meshGradientTexU, 0); uv2[offset + target * 4 + 3] = chr.gradientUv[3] + new Vector2(meshGradientTexU, 0); } if (fontInst.isPacked) { Color32 c = channelSelectColors[chr.channel]; color[offset + target * 4 + 0] = c; color[offset + target * 4 + 1] = c; color[offset + target * 4 + 2] = c; color[offset + target * 4 + 3] = c; } else { color[offset + target * 4 + 0] = meshTopColor; color[offset + target * 4 + 1] = meshTopColor; color[offset + target * 4 + 2] = meshBottomColor; color[offset + target * 4 + 3] = meshBottomColor; } cursorX += (chr.advance + data.spacing) * data.scale.x; if (data.kerning && i < formattedText.Length - 1) { foreach (var k in fontInst.kerning) { if (k.c0 == formattedText[i] && k.c1 == formattedText[i + 1]) { cursorX += k.amount * data.scale.x; break; } } } ++target; } if (alignStartTarget != target) { float lineWidth = cursorX; int alignEndTarget = target; float xOffset = GetXAnchorForWidth(lineWidth, geomData); PostAlignTextData(pos, offset, alignStartTarget, alignEndTarget, xOffset); } for (int i = target; i < data.maxChars; ++i) { pos[offset + i * 4 + 0] = pos[offset + i * 4 + 1] = pos[offset + i * 4 + 2] = pos[offset + i * 4 + 3] = Vector3.zero; uv[offset + i * 4 + 0] = uv[offset + i * 4 + 1] = uv[offset + i * 4 + 2] = uv[offset + i * 4 + 3] = Vector2.zero; if (fontInst.textureGradients) { uv2[offset + i * 4 + 0] = uv2[offset + i * 4 + 1] = uv2[offset + i * 4 + 2] = uv2[offset + i * 4 + 3] = Vector2.zero; } if (!fontInst.isPacked) { color[offset + i * 4 + 0] = color[offset + i * 4 + 1] = meshTopColor; color[offset + i * 4 + 2] = color[offset + i * 4 + 3] = meshBottomColor; } else { color[offset + i * 4 + 0] = color[offset + i * 4 + 1] = color[offset + i * 4 + 2] = color[offset + i * 4 + 3] = Color.clear; } } return(target); }
public void ForceBuild() { if (data.font != null) { _fontInst = data.font.inst; UpdateMaterial(); } Init(true); }
public void CopyFrom(tk2dSpriteCollectionFont src) { active = src.active; bmFont = src.bmFont; texture = src.texture; dupeCaps = src.dupeCaps; flipTextureY = src.flipTextureY; charPadX = src.charPadX; data = src.data; editorData = src.editorData; }