No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TMP_SpriteAssetImporter.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.TextCore;
  4. using UnityEditor;
  5. using System.IO;
  6. using System.Collections.Generic;
  7. using TMPro.EditorUtilities;
  8. using TMPro.SpriteAssetUtilities;
  9. namespace TMPro
  10. {
  11. public class TMP_SpriteAssetImporter : EditorWindow
  12. {
  13. // Create Sprite Asset Editor Window
  14. [MenuItem("Window/TextMeshPro/Sprite Importer", false, 2026)]
  15. public static void ShowFontAtlasCreatorWindow()
  16. {
  17. var window = GetWindow<TMP_SpriteAssetImporter>();
  18. window.titleContent = new GUIContent("Sprite Importer");
  19. window.Focus();
  20. }
  21. Texture2D m_SpriteAtlas;
  22. SpriteAssetImportFormats m_SpriteDataFormat = SpriteAssetImportFormats.TexturePackerJsonArray;
  23. TextAsset m_JsonFile;
  24. string m_CreationFeedback;
  25. TMP_SpriteAsset m_SpriteAsset;
  26. static readonly GUIContent k_ConvertSpriteNameToUnicodeLabel = new GUIContent("Use filenames as Unicodes", "Should sprite filenames be converted and assigned as Unicode code points for each sprite? This conversion assumes the sprite filenames represent valid Unicode code points.");
  27. static bool k_SpriteNameIsUnicodeValue;
  28. /// <summary>
  29. ///
  30. /// </summary>
  31. void OnEnable()
  32. {
  33. // Set Editor Window Size
  34. SetEditorWindowSize();
  35. }
  36. /// <summary>
  37. ///
  38. /// </summary>
  39. public void OnGUI()
  40. {
  41. DrawEditorPanel();
  42. }
  43. /// <summary>
  44. ///
  45. /// </summary>
  46. private void OnDisable()
  47. {
  48. // Clean up sprite asset object that may have been created and not saved.
  49. if (m_SpriteAsset != null && !EditorUtility.IsPersistent(m_SpriteAsset))
  50. DestroyImmediate(m_SpriteAsset);
  51. }
  52. /// <summary>
  53. ///
  54. /// </summary>
  55. void DrawEditorPanel()
  56. {
  57. // label
  58. GUILayout.Label("Import Settings", EditorStyles.boldLabel);
  59. EditorGUI.BeginChangeCheck();
  60. // Sprite Texture Selection
  61. m_JsonFile = EditorGUILayout.ObjectField("Sprite Data Source", m_JsonFile, typeof(TextAsset), false) as TextAsset;
  62. m_SpriteDataFormat = (SpriteAssetImportFormats)EditorGUILayout.EnumPopup("Import Format", m_SpriteDataFormat);
  63. k_SpriteNameIsUnicodeValue = EditorGUILayout.Toggle(k_ConvertSpriteNameToUnicodeLabel, k_SpriteNameIsUnicodeValue);
  64. // Sprite Texture Selection
  65. m_SpriteAtlas = EditorGUILayout.ObjectField("Sprite Texture Atlas", m_SpriteAtlas, typeof(Texture2D), false) as Texture2D;
  66. if (EditorGUI.EndChangeCheck())
  67. {
  68. m_CreationFeedback = string.Empty;
  69. }
  70. GUILayout.Space(10);
  71. GUI.enabled = m_JsonFile != null && m_SpriteAtlas != null && m_SpriteDataFormat != SpriteAssetImportFormats.None;
  72. // Create Sprite Asset
  73. if (GUILayout.Button("Create Sprite Asset"))
  74. {
  75. m_CreationFeedback = string.Empty;
  76. // Clean up sprite asset object that may have been previously created.
  77. if (m_SpriteAsset != null && !EditorUtility.IsPersistent(m_SpriteAsset))
  78. DestroyImmediate(m_SpriteAsset);
  79. // Read json data file
  80. if (m_JsonFile != null)
  81. {
  82. switch (m_SpriteDataFormat)
  83. {
  84. case SpriteAssetImportFormats.TexturePackerJsonArray:
  85. TexturePacker_JsonArray.SpriteDataObject jsonData = null;
  86. try
  87. {
  88. jsonData = JsonUtility.FromJson<TexturePacker_JsonArray.SpriteDataObject>(m_JsonFile.text);
  89. }
  90. catch
  91. {
  92. m_CreationFeedback = "The Sprite Data Source file [" + m_JsonFile.name + "] appears to be invalid or incorrectly formatted.";
  93. }
  94. if (jsonData != null && jsonData.frames != null && jsonData.frames.Count > 0)
  95. {
  96. int spriteCount = jsonData.frames.Count;
  97. // Update import results
  98. m_CreationFeedback = "<b>Import Results</b>\n--------------------\n";
  99. m_CreationFeedback += "<color=#C0ffff><b>" + spriteCount + "</b></color> Sprites were imported from file.";
  100. // Create new Sprite Asset
  101. m_SpriteAsset = CreateInstance<TMP_SpriteAsset>();
  102. // Assign sprite sheet / atlas texture to sprite asset
  103. m_SpriteAsset.spriteSheet = m_SpriteAtlas;
  104. List<TMP_SpriteGlyph> spriteGlyphTable = new List<TMP_SpriteGlyph>();
  105. List<TMP_SpriteCharacter> spriteCharacterTable = new List<TMP_SpriteCharacter>();
  106. PopulateSpriteTables(jsonData, spriteCharacterTable, spriteGlyphTable);
  107. m_SpriteAsset.spriteCharacterTable = spriteCharacterTable;
  108. m_SpriteAsset.spriteGlyphTable = spriteGlyphTable;
  109. }
  110. break;
  111. }
  112. }
  113. }
  114. GUI.enabled = true;
  115. // Creation Feedback
  116. GUILayout.Space(5);
  117. GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Height(60));
  118. {
  119. EditorGUILayout.TextArea(m_CreationFeedback, TMP_UIStyleManager.label);
  120. }
  121. GUILayout.EndVertical();
  122. GUILayout.Space(5);
  123. GUI.enabled = m_JsonFile != null && m_SpriteAtlas && m_SpriteAsset != null;
  124. if (GUILayout.Button("Save Sprite Asset") && m_JsonFile != null)
  125. {
  126. string filePath = EditorUtility.SaveFilePanel("Save Sprite Asset File", new FileInfo(AssetDatabase.GetAssetPath(m_JsonFile)).DirectoryName, m_JsonFile.name, "asset");
  127. if (filePath.Length == 0)
  128. return;
  129. SaveSpriteAsset(filePath);
  130. }
  131. GUI.enabled = true;
  132. }
  133. /// <summary>
  134. ///
  135. /// </summary>
  136. /// <param name="spriteDataObject"></param>
  137. /// <param name="spriteCharacterTable"></param>
  138. /// <param name="spriteGlyphTable"></param>
  139. private static void PopulateSpriteTables(TexturePacker_JsonArray.SpriteDataObject spriteDataObject, List<TMP_SpriteCharacter> spriteCharacterTable, List<TMP_SpriteGlyph> spriteGlyphTable)
  140. {
  141. List<TexturePacker_JsonArray.Frame> importedSprites = spriteDataObject.frames;
  142. float atlasHeight = spriteDataObject.meta.size.h;
  143. for (int i = 0; i < importedSprites.Count; i++)
  144. {
  145. TexturePacker_JsonArray.Frame spriteData = importedSprites[i];
  146. TMP_SpriteGlyph spriteGlyph = new TMP_SpriteGlyph();
  147. spriteGlyph.index = (uint)i;
  148. spriteGlyph.metrics = new GlyphMetrics((int)spriteData.frame.w, (int)spriteData.frame.h, -spriteData.frame.w * spriteData.pivot.x, spriteData.frame.h * spriteData.pivot.y, (int)spriteData.frame.w);
  149. spriteGlyph.glyphRect = new GlyphRect((int)spriteData.frame.x, (int)(atlasHeight - spriteData.frame.h - spriteData.frame.y), (int)spriteData.frame.w, (int)spriteData.frame.h);
  150. spriteGlyph.scale = 1.0f;
  151. spriteGlyphTable.Add(spriteGlyph);
  152. TMP_SpriteCharacter spriteCharacter = new TMP_SpriteCharacter(0xFFFE, spriteGlyph);
  153. // Special handling for .notdef sprite name
  154. string fileNameToLowerInvariant = spriteData.filename.ToLowerInvariant();
  155. if (fileNameToLowerInvariant == ".notdef" || fileNameToLowerInvariant == "notdef")
  156. {
  157. spriteCharacter.name = fileNameToLowerInvariant;
  158. spriteCharacter.unicode = 0;
  159. }
  160. else
  161. {
  162. string spriteName = spriteData.filename.Split('.')[0];
  163. spriteCharacter.name = spriteName;
  164. if (k_SpriteNameIsUnicodeValue)
  165. spriteCharacter.unicode = (uint)TMP_TextUtilities.StringHexToInt(spriteName);
  166. }
  167. spriteCharacter.scale = 1.0f;
  168. spriteCharacterTable.Add(spriteCharacter);
  169. }
  170. }
  171. /// <summary>
  172. ///
  173. /// </summary>
  174. /// <param name="filePath"></param>
  175. void SaveSpriteAsset(string filePath)
  176. {
  177. filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath.
  178. string dataPath = Application.dataPath;
  179. if (filePath.IndexOf(dataPath, System.StringComparison.InvariantCultureIgnoreCase) == -1)
  180. {
  181. Debug.LogError("You're saving the font asset in a directory outside of this project folder. This is not supported. Please select a directory under \"" + dataPath + "\"");
  182. return;
  183. }
  184. string relativeAssetPath = filePath.Substring(dataPath.Length - 6);
  185. string dirName = Path.GetDirectoryName(relativeAssetPath);
  186. string fileName = Path.GetFileNameWithoutExtension(relativeAssetPath);
  187. string pathNoExt = dirName + "/" + fileName;
  188. // Save Sprite Asset
  189. AssetDatabase.CreateAsset(m_SpriteAsset, pathNoExt + ".asset");
  190. // Set version number
  191. m_SpriteAsset.version = "1.1.0";
  192. // Compute the hash code for the sprite asset.
  193. m_SpriteAsset.hashCode = TMP_TextUtilities.GetSimpleHashCode(m_SpriteAsset.name);
  194. // Add new default material for sprite asset.
  195. AddDefaultMaterial(m_SpriteAsset);
  196. }
  197. /// <summary>
  198. /// Create and add new default material to sprite asset.
  199. /// </summary>
  200. /// <param name="spriteAsset"></param>
  201. static void AddDefaultMaterial(TMP_SpriteAsset spriteAsset)
  202. {
  203. Shader shader = Shader.Find("TextMeshPro/Sprite");
  204. Material material = new Material(shader);
  205. material.SetTexture(ShaderUtilities.ID_MainTex, spriteAsset.spriteSheet);
  206. spriteAsset.material = material;
  207. material.name = spriteAsset.name + " Material";
  208. AssetDatabase.AddObjectToAsset(material, spriteAsset);
  209. }
  210. /// <summary>
  211. /// Limits the minimum size of the editor window.
  212. /// </summary>
  213. void SetEditorWindowSize()
  214. {
  215. EditorWindow editorWindow = this;
  216. Vector2 currentWindowSize = editorWindow.minSize;
  217. editorWindow.minSize = new Vector2(Mathf.Max(230, currentWindowSize.x), Mathf.Max(300, currentWindowSize.y));
  218. }
  219. }
  220. }