using UnityEngine; using UnityEngine.UI; using System.Collections; using System.IO; using System.Collections.Generic; using UnityEditor; using UnityEditorInternal; using System.Text.RegularExpressions; using Newtonsoft.Json; using System.Linq; using System; namespace zbitmapfont { public class BitmapFontTool { [MenuItem("Assets/zbitmapfont/Rename")] public static void Rename() { foreach (var a in Selection.assetGUIDs) { var p = AssetDatabase.GUIDToAssetPath(a); if (!System.IO.File.Exists(p)) { continue; } var f = System.IO.Path.GetFileNameWithoutExtension(p); var c = ConvertToChar(f); InputDialog.ShowWindow(c.ToString(), (a) => { if (string.IsNullOrEmpty(a)) { return; } a = ConvertToFileName(a[0]); string b = $"{System.IO.Path.GetDirectoryName(p)}/{a}{System.IO.Path.GetExtension(p)}"; if (System.IO.File.Exists(b)) { Debug.LogError("file existed: " + b); return; } System.IO.File.Move(p, b); System.IO.File.Move(p + ".meta", b + ".meta"); AssetDatabase.Refresh(); }); break; } AssetDatabase.Refresh(); } [MenuItem("Assets/zbitmapfont/CreateBitmapFont")] public static void CreateBitmapFont() { foreach (var a in Selection.assetGUIDs) { var p = AssetDatabase.GUIDToAssetPath(a); if (!System.IO.Directory.Exists(p)) { continue; } string destPath = p; if (!CreateBitmapFont(p, destPath)) { throw new System.Exception("CreateBitmapFont failed: " + p); } } AssetDatabase.Refresh(); } [MenuItem("Assets/zbitmapfont/CreateFontAsset")] public static void CreateFontAsset() { foreach (var a in Selection.assetGUIDs) { var p = AssetDatabase.GUIDToAssetPath(a); if (!System.IO.Directory.Exists(p)) { continue; } string destPath = p; if (!CreateBitmapFont(p, destPath)) { throw new System.Exception("CreateBitmapFont failed: " + p); } CreateBitmapFontMaterial(destPath); CreateFontAsset(destPath); } AssetDatabase.Refresh(); } public static string GetCurrentScriptPath() { System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(true); System.Diagnostics.StackFrame frame = stackTrace.GetFrame(0); string filePath = frame.GetFileName(); return filePath; } static char ConvertToChar(string fileName) { char index = fileName[0]; try { if (fileName.Length == 4) { int temp = System.Convert.ToInt32(fileName, 16); index = (char)temp; } else if (fileName.Length > 1 && fileName[1] == '_') { if (fileName[0] == '_') { index = ' '; } else { index = (char)('A' - 'a' + index); } } } catch (Exception e) { } return index; } static string ConvertToFileName(char c) { string fileName = c.ToString(); try { if (System.IO.Path.GetInvalidFileNameChars().Contains(c)) { fileName = ((int)c).ToString("x4"); } else if (c == ' ') { return "__"; } else if (c >= 'A' && c <= 'Z') { fileName = (char)(c - 'A' + 'a') + "_"; } } catch (Exception e) { } return fileName; } public static bool CreateBitmapFont(string srcPath, string destPath) { destPath = System.IO.Path.GetFullPath(destPath); var paths = System.IO.Directory.GetFiles(srcPath, "*.png", SearchOption.TopDirectoryOnly); List chars = new(); List icons = new(); var sumSize = 0; foreach (var path in paths) { var fileName = Path.GetFileNameWithoutExtension(path); int index = ConvertToChar(fileName); //int index = fileName[0]; //if (fileName.Length == 4) //{ // int temp = System.Convert.ToInt32(fileName, 16); // index = (char)temp; //} //else if (fileName.Length > 1 && fileName[1] == '_') //{ // if (fileName[0] == '_') // { // index = ' '; // } // else // { // index = (char)('A' - 'a' + index); // } //} chars.Add(index); icons.Add($"icon=\"{System.IO.Path.GetFullPath(path)}\",{index},0,0,0"); var tex = AssetDatabase.LoadAssetAtPath(path); sumSize += tex.width * tex.height; } var pngWidth = Mathf.Pow(2, Mathf.CeilToInt(Mathf.Log(Mathf.Sqrt(sumSize), 2))); //var pngWidth = Mathf.CeilToInt(Mathf.Sqrt(sumSize)); var templateConfigStr = System.IO.File.ReadAllText($"{System.IO.Path.GetDirectoryName(GetCurrentScriptPath())}/../template.bmfc"); for (; pngWidth <= 4096; pngWidth *= 2) { var configStr = string.Format(templateConfigStr, string.Join(",", chars), string.Join("\n", icons), pngWidth, pngWidth); var tempPath = $"{destPath}.bmfc"; System.IO.File.WriteAllText(tempPath, configStr); var exePath = $"{System.IO.Path.GetDirectoryName(GetCurrentScriptPath())}/../bmfont1.14a~/bmfont64.com"; var param = $"-c \"{tempPath}\" -o \"{destPath}\""; var ret = CommandLineTool.RunCommand2(exePath, param, Application.dataPath); if (ret.ExitCode != 0) { Debug.LogError(ret.StdErr); Debug.LogError(ret.StdOut); } else { int count = 0; for (int i = 0; true; i++) { var pngPath = $"{destPath}_{i}.png"; if (!System.IO.File.Exists(pngPath)) { break; } else { if (i > 0) { System.IO.File.Delete(pngPath); } } count++; } if (count <= 0) { return false; } if (count == 1) { break; } } } AssetDatabase.Refresh(); { var pngPath = System.IO.Path.GetRelativePath(System.IO.Path.GetDirectoryName(Application.dataPath), $"{destPath}_0.png"); var importer = TextureImporter.GetAtPath(pngPath) as TextureImporter; importer.mipmapEnabled = false; importer.alphaIsTransparency = true; importer.npotScale = TextureImporterNPOTScale.None; importer.SaveAndReimport(); } return true; } static void CreateBitmapFontMaterial(string destPath) { string pngPath = destPath + "_0.png"; Texture2D tex = AssetDatabase.LoadAssetAtPath(pngPath, typeof(Texture2D)) as Texture2D; Shader shader = Shader.Find("UI/Default"); Material material = new Material(shader); material.mainTexture = tex; AssetDatabase.CreateAsset(material, destPath + ".mat"); AssetDatabase.Refresh(); } static void CreateFontAsset(string bitmapfontPath) { var fntPath = $"{bitmapfontPath}.fnt"; var pngPath = $"{bitmapfontPath}_0.png"; var matPath = $"{bitmapfontPath}.mat"; Material mat = AssetDatabase.LoadAssetAtPath(matPath, typeof(Material)) as Material; Texture2D tex = AssetDatabase.LoadAssetAtPath(pngPath, typeof(Texture2D)) as Texture2D; var fntConfigStr = System.IO.File.ReadAllText(fntPath); StringReader sr = new StringReader(fntConfigStr); List charStrs = new(); while (true) { var line = sr.ReadLine(); if (string.IsNullOrEmpty(line)) { break; } if (line.StartsWith("char ")) { charStrs.Add(line); } } CharacterInfo[] charInfos = new CharacterInfo[charStrs.Count]; float fontSize = 0; for (int j = 0; j < charStrs.Count; j++) { var cStr = charStrs[j]; Dictionary charparams = new(); var splitedStrings = cStr.Split(' '); foreach (var a in splitedStrings) { if (a.Contains('=')) { var b = a.Split('='); var key = b[0]; var value = b[1]; charparams.Add(key, int.Parse(value)); } } int index = charparams["id"]; CharacterInfo charInfo = new CharacterInfo(); charInfo.index = index; charInfo.advance = charparams["width"]; { Rect r = new Rect(); r.x = (float)charparams["x"] / tex.width; //r.y = (float)(tex.height - charparams["y"] - charparams["height"]) / tex.height; r.y = (float)(tex.height - charparams["y"]) / tex.height; r.width = (float)charparams["width"] / tex.width; r.height = -(float)charparams["height"] / tex.height; charInfo.uvBottomLeft = new Vector2(r.x, r.y); charInfo.uvBottomRight = new Vector2(r.x + r.width, r.y); charInfo.uvTopLeft = new Vector2(r.x, r.y + r.height); charInfo.uvTopRight = new Vector2(r.x + r.width, r.y + r.height); charInfo.minX = 0; charInfo.minY = charparams["height"] / 2; charInfo.maxX = charparams["width"]; charInfo.maxY = -charparams["height"] / 2; charInfo.advance = charparams["xadvance"]; fontSize = charparams["height"]; } //{ // Vector4 padding = TextureTool.getSpritePadding(info.pivot, info.rect, 1, sprite.rect); // Rect r = new Rect(); // r.x = padding[0]; // r.y = padding[3]; // r.width = info.rect.width; // r.height = info.rect.height; // r.y = -r.y; // r.height = -r.height; // charInfo.vert = r; // fontSize = info.rect.height + Mathf.Abs(padding[1]) + Mathf.Abs(padding[3]); //} charInfos[j] = charInfo; } string fontPath = bitmapfontPath + ".fontsettings"; Font font = null; if (System.IO.File.Exists(fontPath)) { font = AssetDatabase.LoadAssetAtPath(fontPath); } else { font = new Font(); } font.material = mat; font.name = System.IO.Path.GetFileName(bitmapfontPath); font.characterInfo = charInfos; string metaStr = null; if (System.IO.File.Exists(fontPath + ".meta")) { metaStr = System.IO.File.ReadAllText(fontPath + ".meta"); } if (System.IO.File.Exists(fontPath)) { AssetDatabase.SaveAssets(); // System.IO.File.Delete(fontPath); // AssetDatabase.Refresh(); } else { AssetDatabase.CreateAsset(font, fontPath); } AssetDatabase.Refresh(); if (!string.IsNullOrEmpty(metaStr)) { System.IO.File.WriteAllText(fontPath + ".meta", metaStr); } // string content = File.ReadAllText(fontPath); //content = Regex.Replace(content, "(\\s+m_LineSpacing:\\s*)(.*)", "${1}" + fontSize); //content = Regex.Replace(content, "(\\s+m_FontSize:\\s*)(.*)", "${1}" + fontSize); //System.IO.File.WriteAllText(fontPath, content); //AssetDatabase.ImportAsset(fontPath); SerializedObject serializedFont = new SerializedObject(font); SerializedProperty serializedLineSpacing = serializedFont.FindProperty("m_LineSpacing"); serializedLineSpacing.floatValue = fontSize; SerializedProperty serializedFontSize = serializedFont.FindProperty("m_FontSize"); serializedFontSize.floatValue = fontSize; SerializedProperty serializedAscent = serializedFont.FindProperty("m_Ascent"); serializedAscent.floatValue = fontSize / 2; SerializedProperty serializedDescent = serializedFont.FindProperty("m_Descent"); serializedDescent.floatValue = -fontSize / 2; serializedFont.ApplyModifiedProperties(); } } }