BFImporter.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System;
  4. using System.IO;
  5. using System.Text;
  6. namespace litefeel
  7. {
  8. public class BFImporter : AssetPostprocessor
  9. {
  10. static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
  11. {
  12. foreach (string str in importedAssets)
  13. {
  14. //Debug.Log("Reimported Asset: " + str);
  15. DoImportBitmapFont(str);
  16. }
  17. foreach (string str in deletedAssets)
  18. {
  19. //Debug.Log("Deleted Asset: " + str);
  20. DelBitmapFont(str);
  21. }
  22. for (var i = 0; i < movedAssets.Length; i++)
  23. {
  24. //Debug.Log("Moved Asset: " + movedAssets[i] + " from: " + movedFromAssetPaths[i]);
  25. MoveBitmapFont(movedFromAssetPaths[i], movedAssets[i]);
  26. }
  27. }
  28. public static bool IsFnt(string path)
  29. {
  30. return path.EndsWith(".fnt", StringComparison.OrdinalIgnoreCase);
  31. }
  32. public static void DoImportBitmapFont(string fntPatn)
  33. {
  34. if (!IsFnt(fntPatn)) return;
  35. TextAsset fnt = AssetDatabase.LoadMainAssetAtPath(fntPatn) as TextAsset;
  36. string text = fnt.text;
  37. FntParse parse = FntParse.GetFntParse(ref text);
  38. if (parse == null) return;
  39. string fntName = Path.GetFileNameWithoutExtension(fntPatn);
  40. string rootPath = Path.GetDirectoryName(fntPatn);
  41. string fontPath = string.Format("{0}/{1}.fontsettings", rootPath, fntName);
  42. Texture2D[] textures = DoImportTextures(parse, rootPath, fnt);
  43. Font font = AssetDatabase.LoadMainAssetAtPath(fontPath) as Font;
  44. if (font == null)
  45. {
  46. font = new Font();
  47. AssetDatabase.CreateAsset(font, fontPath);
  48. AssetDatabase.WriteImportSettingsIfDirty(fontPath);
  49. AssetDatabase.ImportAsset(fontPath);
  50. }
  51. Material material = AssetDatabase.LoadAssetAtPath(fontPath, typeof(Material)) as Material;
  52. if (material == null)
  53. {
  54. material = new Material(Shader.Find("UI/Default"));
  55. material.name = "Font Material";
  56. AssetDatabase.AddObjectToAsset(material, fontPath);
  57. // unity 5.4+ cannot refresh it immediately, must import it
  58. AssetDatabase.ImportAsset(fontPath);
  59. }
  60. font.material = material;
  61. material.shader = Shader.Find(textures.Length > 1 ? "BFI/Font" + textures.Length : "UI/Default");
  62. material.mainTexture = textures[0];
  63. for (int i = 1; i < textures.Length; i++)
  64. {
  65. material.SetTexture("_MainTex" + (i + 1), textures[i]);
  66. }
  67. font.characterInfo = parse.charInfos;
  68. SerializedObject so = new SerializedObject(font);
  69. so.Update();
  70. so.FindProperty("m_FontSize").floatValue = Mathf.Abs(parse.fontSize);
  71. so.FindProperty("m_LineSpacing").floatValue = parse.lineHeight;
  72. so.FindProperty("m_Ascent").floatValue = parse.lineBaseHeight;
  73. SerializedProperty prop = so.FindProperty("m_Descent");
  74. if (prop != null)
  75. prop.floatValue = parse.lineBaseHeight - parse.lineHeight;
  76. UpdateKernings(so, parse.kernings);
  77. so.ApplyModifiedProperties();
  78. so.SetIsDifferentCacheDirty();
  79. AssetDatabase.SaveAssets();
  80. #if UNITY_5_5_OR_NEWER
  81. // unity 5.5 can not load custom font
  82. ReloadFont(fontPath);
  83. #endif
  84. }
  85. private static Texture2D[] DoImportTextures(FntParse parse, string rootPath, TextAsset fnt)
  86. {
  87. int len = parse.textureNames.Length;
  88. Texture2D[] textures = new Texture2D[len];
  89. for (int i = 0; i < len; i++)
  90. {
  91. // The texture name of the file generated by ShoeBox uses an absolute path
  92. string textureName = Path.GetFileName(parse.textureNames[i]);
  93. string texPath = string.Format("{0}/{1}", rootPath, textureName);
  94. Texture2D texture = AssetDatabase.LoadMainAssetAtPath(texPath) as Texture2D;
  95. if (texture == null)
  96. {
  97. Debug.LogErrorFormat(fnt, "{0}: not found '{1}'.", typeof(BFImporter), texPath);
  98. return textures;
  99. }
  100. TextureImporter texImporter = AssetImporter.GetAtPath(texPath) as TextureImporter;
  101. texImporter.textureType = TextureImporterType.GUI;
  102. texImporter.mipmapEnabled = false;
  103. texImporter.SaveAndReimport();
  104. textures[i] = texture;
  105. }
  106. return textures;
  107. }
  108. private static void UpdateKernings(SerializedObject so, Kerning[] kernings)
  109. {
  110. int len = kernings != null ? kernings.Length : 0;
  111. SerializedProperty kerningsProp = so.FindProperty("m_KerningValues");
  112. if (len == 0)
  113. {
  114. kerningsProp.ClearArray();
  115. return;
  116. }
  117. int propLen = kerningsProp.arraySize;
  118. for (int i = 0; i < len; i++)
  119. {
  120. if (propLen <= i)
  121. {
  122. kerningsProp.InsertArrayElementAtIndex(i);
  123. }
  124. SerializedProperty kerningProp = kerningsProp.GetArrayElementAtIndex(i);
  125. kerningProp.FindPropertyRelative("second").floatValue = kernings[i].amount;
  126. SerializedProperty pairProp = kerningProp.FindPropertyRelative("first");
  127. pairProp.Next(true);
  128. pairProp.intValue = kernings[i].first;
  129. pairProp.Next(false);
  130. pairProp.intValue = kernings[i].second;
  131. }
  132. for (int i = propLen - 1; i >= len; i--)
  133. {
  134. kerningsProp.DeleteArrayElementAtIndex(i);
  135. }
  136. }
  137. private static void DelBitmapFont(string fntPath)
  138. {
  139. if (!IsFnt(fntPath)) return;
  140. string fontPath = fntPath.Substring(0, fntPath.Length - 4) + ".fontsettings";
  141. AssetDatabase.DeleteAsset(fontPath);
  142. }
  143. private static void MoveBitmapFont(string oldFntPath, string nowFntPath)
  144. {
  145. if (!IsFnt(nowFntPath)) return;
  146. string oldFontPath = oldFntPath.Substring(0, oldFntPath.Length - 4) + ".fontsettings";
  147. string nowFontPath = nowFntPath.Substring(0, nowFntPath.Length - 4) + ".fontsettings";
  148. AssetDatabase.MoveAsset(oldFontPath, nowFontPath);
  149. }
  150. // new font can not display via Text in unity 5.5
  151. // must import import it
  152. private static void ReloadFont(string fontPath)
  153. {
  154. var tmpPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
  155. AssetDatabase.ExportPackage(fontPath, tmpPath);
  156. AssetDatabase.DeleteAsset(fontPath);
  157. var startTime = DateTime.Now;
  158. EditorApplication.CallbackFunction func = null;
  159. func = () =>
  160. {
  161. TimeSpan dalt = DateTime.Now - startTime;
  162. if (dalt.TotalSeconds >= 0.1)
  163. {
  164. EditorApplication.update -= func;
  165. AssetDatabase.ImportPackage(tmpPath, false);
  166. File.Delete(tmpPath);
  167. }
  168. };
  169. EditorApplication.update += func;
  170. }
  171. }
  172. }