public static void CreateSDFAsset(TexAsset asset, Font font, string fontPath) { // initialize CheckErr(TMPro_FontPlugin.Initialize_FontEngine()); CheckErr(TMPro_FontPlugin.Load_TrueType_Font(fontPath)); CheckErr(TMPro_FontPlugin.FT_Size_Font(72)); _buffers = new byte[_bufferWidth * _bufferHeight]; var charSet = new int[asset.chars.Length]; _glyphsInfo = new FT_GlyphInfo[asset.chars.Length]; _atlasInfo = null; for (int i = 0; i < asset.chars.Length; i++) { charSet[i] = asset.chars[i].characterIndex; } float strokeSize = _styleStrokeSize; if (_render == RenderModes.DistanceField16) { strokeSize = _styleStrokeSize * 16; } if (_render == RenderModes.DistanceField32) { strokeSize = _styleStrokeSize * 32; } ThreadPool.QueueUserWorkItem(SomeTask => { try { onRendering = true; CheckErr(TMPro_FontPlugin.Render_Characters(_buffers, _bufferWidth, _bufferHeight, _padding, charSet, charSet.Length, _style, strokeSize, true, _render, _optimized ? 4 : 0, ref _faceInfo, _glyphsInfo)); EditorApplication.delayCall += delegate() { try { OnFinished(Convert(asset)); } catch (Exception ex) { Debug.LogException(ex); Debug.LogWarningFormat("Failed to create SDF File for {0}.ttf. Consider delete and rerender again", asset.id); } finally { hasRendered = false; onRendering = false; if (onRenderingBatch > 0) { isRenderingBatchFinished = true; } } }; Debug.LogFormat("Font Rendering of {0}.ttf has completed.", asset.id); } catch (Exception ex) { Debug.LogException(ex); Debug.LogWarningFormat("Failed to create Render {0}.ttf. Consider rerender again", asset.id); } finally { onRendering = false; } }); }
// PRAGMA MARK - Public Interface public static void Bake(Font font, bool useAutoSizing, int fontSize, int characterPadding, TMPFontPackingModes fontPackingMode, int atlasWidth, int atlasHeight, FaceStyles fontStyle, int fontStyleMod, RenderModes fontRenderMode, string charactersToBake, string outputFilePath, TMPFont.GlyphOverride[] glyphOverrides) { int errorCode = TMPro_FontPlugin.Initialize_FontEngine(); if (errorCode != 0 && errorCode != 99) // 99 means that engine was already initialized { Debug.LogWarning("Error Code: " + errorCode + " occurred while initializing TMPro_FontPlugin."); return; } string fontPath = AssetDatabase.GetAssetPath(font); errorCode = TMPro_FontPlugin.Load_TrueType_Font(fontPath); if (errorCode != 0 && errorCode != 99) // 99 means that font was already loaded { Debug.LogWarning("Error Code: " + errorCode + " occurred while loading font: " + font + "."); return; } if (useAutoSizing) { fontSize = 72; } errorCode = TMPro_FontPlugin.FT_Size_Font(fontSize); if (errorCode != 0) { Debug.LogWarning("Error Code: " + errorCode + " occurred while sizing font: " + font + " to size: " + fontSize + "."); return; } byte[] textureBuffer = new byte[atlasWidth * atlasHeight]; int[] characterArray = charactersToBake.Select(c => (int)c).ToArray(); int characterCount = charactersToBake.Length; var fontFaceInfo = new FT_FaceInfo(); var fontGlyphInfo = new FT_GlyphInfo[characterCount]; float strokeSize = fontStyleMod; if (fontRenderMode == RenderModes.DistanceField16) { strokeSize *= 16; } else if (fontRenderMode == RenderModes.DistanceField32) { strokeSize *= 32; } errorCode = TMPro_FontPlugin.Render_Characters(textureBuffer, atlasWidth, atlasHeight, characterPadding, characterArray, characterCount, fontStyle, strokeSize, useAutoSizing, fontRenderMode, (int)fontPackingMode, ref fontFaceInfo, fontGlyphInfo); if (errorCode != 0) { Debug.LogWarning("Error Code: " + errorCode + " occurred while rendering font characters!"); return; } string outputFilename = Path.GetFileNameWithoutExtension(outputFilePath); List <Material> materialReferences = new List <Material>(); // check if font asset already exists TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(outputFilePath, typeof(TMP_FontAsset)) as TMP_FontAsset; if (fontAsset == null) { fontAsset = ScriptableObject.CreateInstance <TMP_FontAsset>(); // Create new TextMeshPro Font Asset. AssetDatabase.CreateAsset(fontAsset, outputFilePath); } else { // Find materials using font atlas as main texture (needed for material presets) materialReferences = FindAssetsByType <Material>() .Where(a => a.mainTexture != null && a.mainTexture.Equals(fontAsset.atlas)) .ToList(); } // Destroy Assets that will be replaced. UnityEngine.Object.DestroyImmediate(fontAsset.atlas, allowDestroyingAssets: true); fontAsset.fontAssetType = (fontRenderMode >= RenderModes.DistanceField16) ? TMP_FontAsset.FontAssetTypes.SDF : TMP_FontAsset.FontAssetTypes.Bitmap; fontAsset.AddFaceInfo(ConvertToFaceInfo(fontFaceInfo)); // Apply glyph overrides var glyphs = ConvertToGlyphs(fontGlyphInfo); foreach (var glyphOverride in glyphOverrides) { var glyph = glyphs.FirstOrDefault(a => a.id == glyphOverride.id); glyph.width = glyphOverride.W; glyph.height = glyphOverride.H; glyph.xOffset = glyphOverride.OX; glyph.yOffset = glyphOverride.OY; glyph.xAdvance = glyphOverride.ADV; glyph.scale = glyphOverride.SF; } fontAsset.AddGlyphInfo(glyphs); var fontTexture = CreateFontTexture(atlasWidth, atlasHeight, textureBuffer, fontRenderMode); fontTexture.name = outputFilename + " Atlas"; fontTexture.hideFlags = HideFlags.HideInHierarchy; fontAsset.atlas = fontTexture; AssetDatabase.AddObjectToAsset(fontTexture, fontAsset); // Find all remaining Materials referencing this font atlas. materialReferences.AddRange(TMP_EditorUtility.FindMaterialReferences(fontAsset) .Where(m => m != null) .ToList()); materialReferences = materialReferences.Distinct().ToList(); if (materialReferences == null || materialReferences.Count <= 0) { // Create new Material and add it as Sub-Asset Shader shader = Shader.Find("TextMeshPro/Distance Field"); Material fontMaterial = new Material(shader); fontMaterial.name = outputFilename + " Material"; fontAsset.material = fontMaterial; fontMaterial.hideFlags = HideFlags.HideInHierarchy; AssetDatabase.AddObjectToAsset(fontMaterial, fontAsset); materialReferences = new List <Material> { fontMaterial }; } foreach (var m in materialReferences) { m.SetTexture(ShaderUtilities.ID_MainTex, fontTexture); m.SetFloat(ShaderUtilities.ID_TextureWidth, fontTexture.width); m.SetFloat(ShaderUtilities.ID_TextureHeight, fontTexture.height); m.SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle); m.SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle); m.SetFloat(ShaderUtilities.ID_GradientScale, characterPadding + 1); } AssetDatabase.SaveAssets(); // Re-import font asset to get the new updated version. AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(fontAsset)); fontAsset.ReadFontDefinition(); AssetDatabase.Refresh(); // NEED TO GENERATE AN EVENT TO FORCE A REDRAW OF ANY TEXTMESHPRO INSTANCES THAT MIGHT BE USING THIS FONT ASSET TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset); }
private void GenerateFontAtlasButton() { if (!m_IsProcessing && m_SourceFontFile != null) { DestroyImmediate(m_FontAtlas); m_FontAtlas = null; m_OutputFeedback = string.Empty; m_SavedFontAtlas = null; int errorCode; errorCode = TMPro_FontPlugin.Initialize_FontEngine(); // Initialize Font Engine if (errorCode != 0) { if (errorCode == 0xF0) { //Debug.Log("Font Library was already initialized!"); errorCode = 0; } else { Debug.Log("Error Code: " + errorCode + " occurred while Initializing the FreeType Library."); } } string fontPath = AssetDatabase.GetAssetPath(m_SourceFontFile); // Get file path of TTF Font. if (errorCode == 0) { errorCode = TMPro_FontPlugin.Load_TrueType_Font(fontPath); // Load the selected font. if (errorCode != 0) { if (errorCode == 0xF1) { //Debug.Log("Font was already loaded!"); errorCode = 0; } else { Debug.Log("Error Code: " + errorCode + " occurred while Loading the [" + m_SourceFontFile.name + "] font file. This typically results from the use of an incompatible or corrupted font file."); } } } if (errorCode == 0) { if (m_PointSizeSamplingMode == 0) { m_PointSize = 72; // If Auto set size to 72 pts. } errorCode = TMPro_FontPlugin.FT_Size_Font(m_PointSize); // Load the selected font and size it accordingly. if (errorCode != 0) { Debug.Log("Error Code: " + errorCode + " occurred while Sizing the font."); } } // Define an array containing the characters we will render. if (errorCode == 0) { int[] characterSet; if (m_CharacterSetSelectionMode == 7 || m_CharacterSetSelectionMode == 8) { List <int> charList = new List <int>(); for (int i = 0; i < m_CharacterSequence.Length; i++) { // Check to make sure we don't include duplicates if (charList.FindIndex(item => item == m_CharacterSequence[i]) == -1) { charList.Add(m_CharacterSequence[i]); } else { //Debug.Log("Character [" + characterSequence[i] + "] is a duplicate."); } } characterSet = charList.ToArray(); } else if (m_CharacterSetSelectionMode == 6) { characterSet = ParseHexNumberSequence(m_CharacterSequence); } else { characterSet = ParseNumberSequence(m_CharacterSequence); } m_CharacterCount = characterSet.Length; m_TextureBuffer = new byte[m_AtlasWidth * m_AtlasHeight]; m_FontFaceInfo = new FT_FaceInfo(); m_FontGlyphInfo = new FT_GlyphInfo[m_CharacterCount]; int padding = m_Padding; bool autoSizing = m_PointSizeSamplingMode == 0; float strokeSize = m_FontStyleValue; if (m_RenderMode == RenderModes.DistanceField16) { strokeSize = m_FontStyleValue * 16; } if (m_RenderMode == RenderModes.DistanceField32) { strokeSize = m_FontStyleValue * 32; } m_IsProcessing = true; m_IsGenerationCancelled = false; // Start Stop Watch m_StopWatch = System.Diagnostics.Stopwatch.StartNew(); ThreadPool.QueueUserWorkItem(someTask => { m_IsRenderingDone = false; errorCode = TMPro_FontPlugin.Render_Characters(m_TextureBuffer, m_AtlasWidth, m_AtlasHeight, padding, characterSet, m_CharacterCount, m_FontStyle, strokeSize, autoSizing, m_RenderMode, (int)m_PackingMode, ref m_FontFaceInfo, m_FontGlyphInfo); ThreadRenderBackupFont(0, m_AtlasWidth); m_IsRenderingDone = true; }); } } }
private void ThreadRenderBackupFont(int backupLevel, int xOffsetDist) { if (m_FontBackupPaths == null || m_FontBackupPaths.Length <= backupLevel) { return; } List <int> list = new List <int>(); for (int index = 0; index < m_CharacterCount; ++index) { if (m_FontGlyphInfo[index].x == -1) { list.Add(m_FontGlyphInfo[index].id); } } // 如果有指定字体,则在这里插入 if (m_CharacterUseFontBackup != null && m_CharacterUseFontBackup.Length > backupLevel) { foreach (var character in m_CharacterUseFontBackup[backupLevel]) { if (!string.IsNullOrEmpty(character)) { for (int i = 0; i < character.Length; i++) { // Check to make sure we don't include duplicates if (list.FindIndex(item => item == character[i]) == -1) { list.Add(character[i]); } } } } } if (list.Count == 0) { return; } int[] characterSet = list.ToArray(); string fontPath = m_FontBackupPaths[backupLevel]; int errorCode = TMPro_FontPlugin.Load_TrueType_Font(fontPath); if (errorCode != 0) { return; } var tmpAtlasWidth = 512; var tmpAtlasHeight = 512; var tmpTextureBuffer = new byte[tmpAtlasWidth * tmpAtlasHeight]; var tmpCharacterCount = characterSet.Length; var tmpFontFaceInfo = default(FT_FaceInfo); var tmpFontGlyphInfo = new FT_GlyphInfo[tmpCharacterCount]; bool autoSizing = m_PointSizeSamplingMode == 0; float strokeSize = m_FontStyleValue; if (m_RenderMode == RenderModes.DistanceField16) { strokeSize = m_FontStyleValue * 16; } if (m_RenderMode == RenderModes.DistanceField32) { strokeSize = m_FontStyleValue * 32; } errorCode = TMPro_FontPlugin.Render_Characters(tmpTextureBuffer, tmpAtlasWidth, tmpAtlasHeight, m_Padding, characterSet, tmpCharacterCount, m_FontStyle, strokeSize, autoSizing, m_RenderMode, (int)m_PackingMode, ref tmpFontFaceInfo, tmpFontGlyphInfo); if (errorCode != 0) { return; } int wordWidth = m_PointSize; int xStart = xOffsetDist - m_Padding * 2 - wordWidth; // 从padding开始拷贝,否则会出现负偏移丢失的情况 int yStart = m_AtlasHeight - m_Padding - 1; int numY = 0; for (int index = 0; index < tmpCharacterCount; ++index) { if (!Mathf.Approximately(tmpFontGlyphInfo[index].x, -1)) { var gi = tmpFontGlyphInfo[index]; var x = Mathf.FloorToInt(gi.x) - m_Padding; var y = tmpAtlasHeight - (Mathf.FloorToInt(gi.y) - m_Padding); var w = Mathf.CeilToInt(gi.width) + m_Padding * 2; var h = Mathf.CeilToInt(gi.height) + m_Padding * 2; for (int r = 0; r < h; r++) { for (int c = 0; c < w; c++) { m_TextureBuffer[(yStart - r) * m_AtlasWidth + c + xStart] = tmpTextureBuffer[(y - r) * tmpAtlasWidth + c + x]; } } var idx = ArrayUtility.FindIndex(m_FontGlyphInfo, info => info.id == gi.id); if (idx == -1) { // 往数组里面添加 ArrayUtility.Add(ref m_FontGlyphInfo, new FT_GlyphInfo() { id = gi.id }); idx = m_FontGlyphInfo.Length - 1; } var gi2 = m_FontGlyphInfo[idx]; gi2.x = xStart + m_Padding; gi2.y = m_AtlasHeight - yStart + m_Padding; gi2.width = gi.width; gi2.height = gi.height; gi2.xAdvance = gi.xAdvance; gi2.xOffset = gi.xOffset; gi2.yOffset = gi.yOffset; m_FontGlyphInfo[idx] = gi2; yStart = yStart - h - m_Padding - 1; numY++; // 如果超过五个则换一列 if (numY > 5) { numY = 0; xStart = xStart - m_Padding * 2 - wordWidth; yStart = m_AtlasHeight - m_Padding - 1; } } } ThreadRenderBackupFont(++backupLevel, xStart); }
public static void CreateSDFAsset(TexFont font, string fontPath) { // Simple checks... if (!font.Font_Asset) { return; } // Expensive check, somewhat useless /*var objs = AssetDatabase.FindAssets("t:TMP_FontAsset"); * foreach (var obj in objs) * { * var asset = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(AssetDatabase.GUIDToAssetPath(obj)); * if (asset.name == font.name) * { * font.SDF_Asset = asset; * return; * } * }*/ //TMPro_FontPlugin.LinkDebugLog(); var error = 0; error = TMPro_FontPlugin.Initialize_FontEngine(); if (error != 0 && error != 99) { throw new Exception("ERROR: " + error.ToString()); } error = TMPro_FontPlugin.Load_TrueType_Font(fontPath); if (error != 0 && error != 99) { throw new Exception("ERROR: " + error.ToString()); } error = TMPro_FontPlugin.FT_Size_Font(72); if (error != 0 && error != 99) { throw new Exception("ERROR: " + error.ToString()); } _buffers = new byte[_bufferWidth * _bufferHeight]; var charSet = new int[font.chars.Length]; _glyphsInfo = new FT_GlyphInfo[font.chars.Length]; _atlasInfo = null; for (int i = 0; i < font.chars.Length; i++) { charSet[i] = font.chars[i].characterIndex; } float strokeSize = _styleStrokeSize; if (_render == RenderModes.DistanceField16) { strokeSize = _styleStrokeSize * 16; } if (_render == RenderModes.DistanceField32) { strokeSize = _styleStrokeSize * 32; } EditorApplication.update += OnUpdate; _renderedFont = font; ThreadPool.QueueUserWorkItem(SomeTask => { onRendering = true; error = TMPro_FontPlugin.Render_Characters(_buffers, _bufferWidth, _bufferHeight, _padding, charSet, charSet.Length, _style, strokeSize, true, _render, _optimized ? 4 : 0, ref _faceInfo, _glyphsInfo); if (error != 0 && error != 99) { onRendering = false; throw new Exception("ERROR: " + error.ToString()); } // Can't call OnFinished here because this isn't a Main thread hasRendered = true; Debug.LogFormat("Font Rendering of {0}.ttf is completed.", font.id); }); }