public static string PickAllCharsRangeFromFont(Font p_font) { string v_charsRange = ""; if (p_font != null) { TrueTypeFontImporter v_fontReimporter = null; //A GLITCH: Unity's Font.CharacterInfo doesn't work //properly on dynamic mode, we need to change it to Unicode first if (p_font.dynamic) { var assetPath = AssetDatabase.GetAssetPath(p_font); v_fontReimporter = (TrueTypeFontImporter)AssetImporter.GetAtPath(assetPath); v_fontReimporter.fontTextureCase = FontTextureCase.Unicode; v_fontReimporter.SaveAndReimport(); } //Only Non-Dynamic Fonts define the characterInfo array Vector2Int v_minMaxRange = new Vector2Int(-1, -1); for (int i = 0; i < p_font.characterInfo.Length; i++) { var v_charInfo = p_font.characterInfo[i]; var v_apply = true; if (v_minMaxRange.x < 0 || v_minMaxRange.y < 0) { v_apply = false; v_minMaxRange = new Vector2Int(v_charInfo.index, v_charInfo.index); } else if (v_charInfo.index == v_minMaxRange.y + 1) { v_apply = false; v_minMaxRange.y = v_charInfo.index; } if (v_apply || i == p_font.characterInfo.Length - 1) { if (!string.IsNullOrEmpty(v_charsRange)) { v_charsRange += "\n,"; } v_charsRange += v_minMaxRange.x + "-" + v_minMaxRange.y; if (i == p_font.characterInfo.Length - 1) { if (v_charInfo.index >= 0 && (v_charInfo.index < v_minMaxRange.x || v_charInfo.index > v_minMaxRange.y)) { v_charsRange += "\n," + v_charInfo.index + "-" + v_charInfo.index; } } else { v_minMaxRange = new Vector2Int(v_charInfo.index, v_charInfo.index); } } } // Change back to dynamic font if (v_fontReimporter != null) { v_fontReimporter.fontTextureCase = FontTextureCase.Dynamic; v_fontReimporter.SaveAndReimport(); } } return(v_charsRange); }
/// <summary> /// Create Soft Font, Soft Font Material, Soft Font Texture from SoftEffect Settings, /// </summary> /// <param name="font"></param> private void CreateSoftFont(Font font, bool createNewFolder) // http://answers.unity3d.com/questions/485695/truetypefontimportergenerateeditablefont-does-not.html { // Mkey.Utils.Measure("<<<<<<<<<<<<Summary CreateSoftFontTexture>>>>>>>>>>>>>>>: ", () => { gpuWorker = new GPUWorker(eShader); string dirPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(font)); //1) load source font asset string path = AssetDatabase.GetAssetPath(font); Font f = font; if (SoftEffects.debuglog) { Debug.Log("Path to Source font: " + path); } font = (Font)AssetDatabase.LoadMainAssetAtPath(path); if (f && !font) { Debug.LogError("Can't use embedded font : " + f.name); return; } //2) Remove old Editable font if (SoftFont && !createNewFolder) { if (SoftEffects.debuglog) { Debug.Log("EditableFont folder: " + Path.GetDirectoryName(AssetDatabase.GetAssetPath(SoftFont))); } if (SoftEffects.debuglog) { Debug.Log("Remove old EditableFont: " + SoftFont.name); } if (SoftFont.material) { AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(SoftFont.material.mainTexture)); AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(SoftFont.material)); } AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(SoftFont)); AssetDatabase.Refresh(); } //3) reimport source font as editable TrueTypeFontImporter fontImporter = AssetImporter.GetAtPath(path) as TrueTypeFontImporter; //source settings int sourceSize = fontImporter.fontSize; int sourcePadding = fontImporter.characterPadding; int sourceSpacing = fontImporter.characterSpacing; FontTextureCase sourceCase = fontImporter.fontTextureCase; string chars = fontImporter.customCharacters; fontImporter.fontSize = GetComponent <Text>().fontSize; fontImporter.characterPadding = Mathf.Clamp(faceOptions.extPixels, 1, 100); fontImporter.characterSpacing = 0; // Mkey.Utils.Measure("Summary PreCreateFontTexture: ", () => { // Mkey.Utils.Measure("Reimport font: ", () => { if (SoftFontTextureCase == FontTextureCase.CustomSet) { if (customCharacters.Length == 0 || customCharacters == " ") { Debug.LogError("Custom Characters string is empty. Set default string."); customCharacters = GetComponent <Text>().text; if (customCharacters.Length == 0 || customCharacters == " ") { customCharacters = "New txt"; } } fontImporter.customCharacters = customCharacters; } else if (SoftFontTextureCase == FontTextureCase.Dynamic) { SoftFontTextureCase = FontTextureCase.ASCII; } fontImporter.fontTextureCase = SoftFontTextureCase; fontImporter.SaveAndReimport(); // }); // Mkey.Utils.Measure("GenerateEditableFont: ", () => { SoftFont = fontImporter.GenerateEditableFont(path); // }); int maxSize = Mathf.Max(font.material.mainTexture.width, font.material.mainTexture.height); // Mkey.Utils.Measure("RenameAsset: ", () => { AssetDatabase.RenameAsset(AssetDatabase.GetAssetPath(SoftFont), font.name + key); AssetDatabase.RenameAsset(AssetDatabase.GetAssetPath(SoftFont.material), font.name + key + "_edit"); AssetDatabase.RenameAsset(AssetDatabase.GetAssetPath(SoftFont.material.mainTexture), font.name + key); AssetDatabase.Refresh(); // }); Shader softShader = Shader.Find("SoftEffects/SoftEditShader"); SoftFont.material.shader = softShader; SoftMaterial = SoftFont.material; if (SoftEffects.debuglog) { Debug.Log("Editable texture size: " + SoftFont.material.mainTexture.width + " x " + SoftFont.material.mainTexture.height); } // Mkey.Utils.Measure("Reimport texture: ", () => { //5) Reimport EditableFont texture as readable SoftFont.material.mainTexture.ReimportTexture(true, maxSize); if (SoftEffects.debuglog) { Debug.Log("Editable texture size after reimport: " + SoftFont.material.mainTexture.width + " x " + SoftFont.material.mainTexture.height); } // }); // }); //5) Generate new Texture for editable font // Mkey.Utils.Measure("faceOptions.RenderFontTexture: ", () => { faceOptions.RenderFontTexture(gpuWorker, SoftFont, cb); //}); // Mkey.Utils.Measure("AfterCreateFontTexture: ", () => { faceOptions.CreateTextureFromRender_ARGB32(true, dirPath + "/" + font.name + key + "_edit" + ".png"); AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(SoftFont.material.mainTexture)); // Remove old texture Texture2D t = (Texture2D)AssetDatabase.LoadMainAssetAtPath(dirPath + "/" + font.name + key + "_edit" + ".png"); // load new texture asset t.ReimportTexture(true); //6 extend verts and uvs // SoftFont.ExtendVertsAndUvs(faceOptions.extPixels); faceOptions.mainTexture = t; AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); // 9) remove editable font to unique folder string targetFolder = AssetDatabase.GUIDToAssetPath(FolderGUID); string fontPath = AssetDatabase.GetAssetPath(SoftFont); string materialPath = AssetDatabase.GetAssetPath(SoftFont.material); string texturePath = AssetDatabase.GetAssetPath(t); if (SoftEffects.debuglog) { Debug.Log("Move file: " + fontPath + " to : " + targetFolder + "/" + Path.GetFileName(fontPath)); } AssetDatabase.MoveAsset(fontPath, targetFolder + "/" + Path.GetFileName(fontPath));// FileUtil.MoveFileOrDirectory(fontPath, targetFolder + "/"+ Path.GetFileName(fontPath)); AssetDatabase.MoveAsset(materialPath, targetFolder + "/" + Path.GetFileName(materialPath)); AssetDatabase.MoveAsset(texturePath, targetFolder + "/" + Path.GetFileName(texturePath)); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); faceOptions.IsCombinedDirty = true; RenderNewTextures(gpuWorker, true); /**/ EditorGUIUtility.PingObject(SoftFont); EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); //revert source settings fontImporter = AssetImporter.GetAtPath(path) as TrueTypeFontImporter; fontImporter.fontSize = sourceSize; fontImporter.fontTextureCase = sourceCase; // fontImporter.characterPadding = sourcePadding; // fontImporter.characterSpacing = sourceSpacing; fontImporter.characterPadding = 1; fontImporter.characterSpacing = 0; if (sourceCase == FontTextureCase.CustomSet) { fontImporter.customCharacters = chars; } fontImporter.SaveAndReimport(); // }); // }); }
private void GenerateAtlas() { TrueTypeFontImporter fontImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(FontToConvert)) as TrueTypeFontImporter; if (fontImporter == null) { Debug.LogError("Could not import mesh asset! Builtin Unity fonts like Arial don't work unless you put them in the project directory!"); } fontImporter.characterSpacing = 4; fontImporter.characterPadding = 2; fontImporter.SaveAndReimport(); // Hacky method to get the generated font texture so that we can figure out where to put pixels Texture2D fontTexture = AssetDatabase.LoadAssetAtPath <Texture2D>(AssetDatabase.GetAssetPath(FontToConvert)); Dictionary <CharacterInfo, Texture2D> characterGlyphMap = new Dictionary <CharacterInfo, Texture2D>(); CharacterInfo[] characterInfos = FontToConvert.characterInfo; Texture2D newAtlas = new Texture2D(fontTexture.width, fontTexture.height, TextureFormat.ARGB32, false, true); for (int x = 0; x < newAtlas.width; ++x) { for (int y = 0; y < newAtlas.height; ++y) { newAtlas.SetPixel(x, y, Color.black); } } int charCount = 0; foreach (CharacterInfo info in characterInfos) { charCount++; EditorUtility.DisplayProgressBar("Generating MSDF Atlas...", string.Format("Glyph {0}/{1}", charCount, characterInfos.Length), charCount / (float)characterInfos.Length); Texture2D currentGlyphTex = GenerateGlyphTexture(info.index, info.glyphWidth, info.glyphHeight); if (currentGlyphTex == null) { continue; } for (int x = 0; x < currentGlyphTex.width; ++x) { for (int y = 0; y < currentGlyphTex.height; ++y) { float progressX = (x) / (float)(currentGlyphTex.width); float progressY = (y) / (float)(currentGlyphTex.height); float uvProgressX = Mathf.Lerp(info.uvTopLeft.x, info.uvTopRight.x, progressX) * fontTexture.width; float uvProgressY = Mathf.Lerp(info.uvBottomLeft.y, info.uvTopLeft.y, progressY) * fontTexture.height; // flipped iS dEpRiCaTeD uSiNg ThE Uv WiLl bE CoNSiStEnT. It's not consistent in my limited experience. // Maybe I'm doing something wrong, but I don't want to try fighting with Unity trying to fix an issue that may be on their end.. I've wasted enough time on trusting Unity to do things correctly. #pragma warning disable 0618 if (info.flipped) #pragma warning restore 0618 { uvProgressY = Mathf.Lerp(info.uvTopLeft.y, info.uvTopRight.y, progressX) * fontTexture.height; uvProgressX = Mathf.Lerp(info.uvBottomLeft.x, info.uvTopLeft.x, progressY) * fontTexture.width; } int targetX = Mathf.RoundToInt(uvProgressX); int targetY = Mathf.RoundToInt(uvProgressY) - 1; Color glyphCol = currentGlyphTex.GetPixel(x, y); newAtlas.SetPixel(targetX, targetY, glyphCol); } } } newAtlas.Apply(false); if (UseTextureCompression) { EditorUtility.DisplayProgressBar("Generating MSDF Atlas...", "Compressing Atlas...", 1f); EditorUtility.CompressTexture(newAtlas, TextureFormat.BC7, UnityEditor.TextureCompressionQuality.Best); } EditorUtility.ClearProgressBar(); string fontPath = AssetDatabase.GetAssetPath(FontToConvert); string savePath = Path.Combine(Path.GetDirectoryName(fontPath), Path.GetFileNameWithoutExtension(fontPath) + "_msdfAtlas.asset"); AssetDatabase.CreateAsset(newAtlas, savePath); EditorGUIUtility.PingObject(newAtlas); }
private void GenerateAtlas() { TrueTypeFontImporter fontImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(FontToConvert)) as TrueTypeFontImporter; if (fontImporter == null) { Debug.LogError("Could not import mesh asset! Builtin Unity fonts like Arial don't work unless you put them in the project directory!"); } fontImporter.characterSpacing = 4; fontImporter.characterPadding = 2; fontImporter.SaveAndReimport(); int tilemapsize = TileSize * 16; Texture2D newAtlas = new Texture2D(tilemapsize, tilemapsize, TextureFormat.ARGB32, false, true); for (int x = 0; x < newAtlas.width; ++x) { for (int y = 0; y < newAtlas.height; ++y) { newAtlas.SetPixel(x, y, Color.black); } } for (int i = 1; i < 256; i++) { char c = (char)i; if (!IncludeAllGlyphs && !FontToConvert.HasCharacter(c)) { continue; } EditorUtility.DisplayProgressBar("Generating MSDF Tileset...", string.Format("Glyph {0}/256", i + 1), i / 255.0f); Texture2D currentGlyphTex = GenerateGlyphTexture(i, TileSize - Padding, TileSize - Padding); if (currentGlyphTex == null) { continue; } int tileindex = i - (OffByOne ? 1 : 0); int rowoffset = TileSize * (tileindex / 16) + Padding / 2; int columnoffset = TileSize * (tileindex % 16) + Padding / 2; for (int y = 0; y < currentGlyphTex.height; ++y) { for (int x = 0; x < currentGlyphTex.width; ++x) { Color glyphCol = currentGlyphTex.GetPixel(x, currentGlyphTex.height - 1 - y); newAtlas.SetPixel(columnoffset + x, tilemapsize - 1 - (rowoffset + y), glyphCol); } } } newAtlas.Apply(false); if (UseTextureCompression) { EditorUtility.DisplayProgressBar("Generating MSDF Tileset...", "Compressing Tileset...", 1f); EditorUtility.CompressTexture(newAtlas, TextureFormat.BC7, UnityEditor.TextureCompressionQuality.Best); } EditorUtility.ClearProgressBar(); string savePath = getResultPath() + ".asset"; AssetDatabase.CreateAsset(newAtlas, savePath); /*Texture2D outtex = AssetDatabase.LoadAssetAtPath<Texture2D>(savePath); * if (outtex != null) * { * outtex = newAtlas; * AssetDatabase.ForceReserializeAssets(); * } * else * { * AssetDatabase.CreateAsset(newAtlas, savePath); * }*/ EditorGUIUtility.PingObject(newAtlas); }
//[MenuItem("Assets/Create Editable Copy Font")] static void CreateFont() { var txts = UnityEngine.Object.FindObjectsOfType(typeof(Text)); return; TextAsset sourceTextAsset = null; try { sourceTextAsset = (TextAsset)Selection.activeObject; } catch (InvalidCastException e) { Debug.Log("Selected Object is not a txt file: " + Environment.NewLine + e.Message); } if (sourceTextAsset == null) { EditorUtility.DisplayDialog("No Config selected", "Please select a TxtFile Config...\nSuch as Exsample.txt:\nname=Assets/GameAssets/Fonts/impact.ttf,size=40\n123456789abcdefghijk", "Cancel"); return; } int targetFontSize; string sourceFontPath, targetFontPath, targetFontCharacters = ""; try { string sourceConfigPath = AssetDatabase.GetAssetPath(Selection.activeObject); string[] sourceConfigInfos = sourceTextAsset.text.Split('\n'); string headInfo = sourceConfigInfos [0]; string[] headInfos = headInfo.Split(','); sourceFontPath = headInfos [0].Split('=') [1]; targetFontPath = sourceConfigPath.Replace(".txt", "_copy"); targetFontSize = int.Parse(headInfos [1].Split('=') [1]); for (int i = 1; i < sourceConfigInfos.Length; i++) { targetFontCharacters += sourceConfigInfos [i]; } } catch (Exception ex) { EditorUtility.DisplayDialog("Config Error", "The config header data error...", "Cancel"); return; } // 重新生成字体文件会导致场景中已存在的丢失, // 所以需要生成后再次赋值 string[] targetFontPathInfos = targetFontPath.Split('/'); string textCheckName = targetFontPathInfos [targetFontPathInfos.Length - 1]; var listTexts = new List <Text>(); foreach (Text text in UnityEngine.Object.FindObjectsOfType(typeof(Text))) { if (text.font.name == textCheckName) { listTexts.Add(text); } } UnityEngine.Object f = AssetDatabase.LoadMainAssetAtPath(sourceFontPath); string path = AssetDatabase.GetAssetPath(f); TrueTypeFontImporter fontImporter = AssetImporter.GetAtPath(path) as TrueTypeFontImporter; fontImporter.fontTextureCase = FontTextureCase.CustomSet; fontImporter.customCharacters = targetFontCharacters; fontImporter.fontSize = targetFontSize; fontImporter.SaveAndReimport(); AssetDatabase.Refresh(); Font font = fontImporter.GenerateEditableFont(targetFontPath); foreach (Text item in listTexts) { item.font = font; } // 还原ttf设置 fontImporter.fontTextureCase = FontTextureCase.Dynamic; fontImporter.SaveAndReimport(); AssetDatabase.Refresh(); System.GC.Collect(); }
// レイアウトを描画する private void OnGUI() { string tPath = null; string[] tId = AssetDatabase.FindAssets("FontFilter"); if (tId != null) { int i, l = tId.Length; for (i = 0; i < l; i++) { tPath = AssetDatabase.GUIDToAssetPath(tId[i]); if (Directory.Exists(tPath) == true) { break; } } if (i >= l) { tPath = null; } } if (string.IsNullOrEmpty(tPath) == true) { EditorGUILayout.HelpBox("状態が異常です", MessageType.Warning); return; } tPath = tPath + "/Resources/uGUIHelper"; if (Directory.Exists(tPath) == false) { EditorGUILayout.HelpBox("保存フォルダが存在しません", MessageType.Warning); return; } FontFilter tFF = null; tPath = tPath + "/FontFilter.asset"; if (File.Exists(tPath) == false) { // ファイルが存在しない tFF = ScriptableObject.CreateInstance <FontFilter>(); tFF.name = "FontFilter"; AssetDatabase.CreateAsset(tFF, tPath); AssetDatabase.Refresh(); } else { // ファイルが存在する tFF = AssetDatabase.LoadAssetAtPath <FontFilter>(tPath); } Selection.activeObject = tFF; //---------------------------------------------------------- bool tDirty = false; // フォント Font tFont = EditorGUILayout.ObjectField("Font", m_Font, typeof(Font), false) as Font; if (tFont != m_Font) { m_Font = tFont; } if (m_Font != null) { if (GUILayout.Button("Create Or Update") == true) { tPath = AssetDatabase.GetAssetPath(m_Font.GetInstanceID()); TrueTypeFontImporter tFontData = ( TrueTypeFontImporter )AssetImporter.GetAtPath(tPath); FontTextureCase tOldFontTextureCase = tFontData.fontTextureCase; if (tFontData.fontTextureCase != FontTextureCase.Unicode) { tFontData.fontTextureCase = FontTextureCase.Unicode; tFontData.SaveAndReimport(); } //-------------------------------------------------------------------- if (tFF.flag == null || tFF.flag.Length < 8192) { tFF.flag = new byte[8192]; } int v = 0; byte f; CharacterInfo tCI; bool e; char c; int i, j, l = 65536; for (i = 0; i < l; i = i + 8) { f = 0; for (j = 0; j < 8; j++) { c = ( char )(i + j); e = true; if (c != ' ' && c != ' ') { if (m_Font.HasCharacter(c) == true) { if (m_Font.GetCharacterInfo(c, out tCI, 16) == true) { if (tCI.advance <= 0) { e = false; } } else { e = false; } } else { e = false; } } if (e == true) { f = ( byte )(f | (1 << j)); v++; } } tFF.flag[i >> 3] = f; } //-------------------------------------------------------------------- if (tOldFontTextureCase != FontTextureCase.Unicode) { tFontData.fontTextureCase = tOldFontTextureCase; tFontData.SaveAndReimport(); } //-------------------------------------------------------------------- tDirty = true; EditorUtility.DisplayDialog("Font Filter", "Completed !! -> " + v, "OK"); } } //---------------------------------- // 更新判定 if (tDirty == true) { EditorUtility.SetDirty(tFF); // 更新実行 // AssetDatabase.Refresh() ; } }
public void PopulateCharacter() { //A GLITCH: Unity's Font.HasCharacter doesn't work properly on dynamic mode, we need to change it to Unicode first TrueTypeFontImporter fontData = (TrueTypeFontImporter)AssetImporter.GetAtPath(assetPath); if (!fontData) { assetPath = AssetDatabase.GetAssetPath(Font_Asset); fontData = (TrueTypeFontImporter)AssetImporter.GetAtPath(assetPath); } fontData.customCharacters = parsedCatalogs == null || parsedCatalogs.Length == 0 ? null : new System.String(parsedCatalogs); fontData.fontTextureCase = string.IsNullOrEmpty(fontData.customCharacters) ? FontTextureCase.Unicode : FontTextureCase.CustomSet; fontData.SaveAndReimport(); chars = chars ?? new TexChar[0]; TexChar ch; // Import all or on what parsedCatalogs says var availableChars = Font_Asset.characterInfo; var newChars = new TexChar[parsedCatalogs.Length == 0 ? availableChars.Length : parsedCatalogs.Length]; // Try to keep the character data not destroyed at all. for (int i = 0; i < newChars.Length; i++) { if (parsedCatalogs.Length == 0) { ch = newChars[i] = chars.FirstOrDefault(x => x.characterIndex == availableChars[i].index) ?? new TexChar(this, i, (char)availableChars[i].index, true, 1); } else { ch = newChars[i] = chars.FirstOrDefault(x => x.characterIndex == parsedCatalogs[i]) ?? new TexChar(this, i, parsedCatalogs[i], Font_Asset.HasCharacter(parsedCatalogs[i]), 1); } if (!ch.supported) { continue; } CharacterInfo c; Font_Asset.GetCharacterInfo(ch.characterIndex, out c, 0, FontStyle.Normal); float factor = c.size == 0 ? Font_Asset.fontSize : c.size; ch.depth = -c.minY / factor; ch.height = c.maxY / factor; ch.bearing = -c.minX / factor; ch.italic = c.maxX / factor; ch.width = c.advance / factor; ch.fontIndex = index; ch.index = i; } chars = newChars; font_lineHeight = Mathf.Max(Font_Asset.lineHeight / Font_Asset.fontSize, 0.2f); // Try to keep the character data not destroyed at all. for (int i = 0; i < newChars.Length; i++) { chars = newChars; } fontData.fontTextureCase = FontTextureCase.Dynamic; fontData.SaveAndReimport(); }