TMP_SpriteAsset.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. using UnityEngine;
  2. using UnityEngine.TextCore;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace TMPro
  6. {
  7. public class TMP_SpriteAsset : TMP_Asset
  8. {
  9. internal Dictionary<uint, int> m_UnicodeLookup;
  10. internal Dictionary<int, int> m_NameLookup;
  11. internal Dictionary<uint, int> m_GlyphIndexLookup;
  12. /// <summary>
  13. /// The version of the sprite asset class.
  14. /// Version 1.1.0 updates the asset data structure to be compatible with new font asset structure.
  15. /// </summary>
  16. public string version
  17. {
  18. get { return m_Version; }
  19. internal set { m_Version = value; }
  20. }
  21. [SerializeField]
  22. private string m_Version;
  23. // The texture which contains the sprites.
  24. public Texture spriteSheet;
  25. public List<TMP_SpriteCharacter> spriteCharacterTable
  26. {
  27. get
  28. {
  29. if (m_GlyphIndexLookup == null)
  30. UpdateLookupTables();
  31. return m_SpriteCharacterTable;
  32. }
  33. internal set { m_SpriteCharacterTable = value; }
  34. }
  35. [SerializeField]
  36. private List<TMP_SpriteCharacter> m_SpriteCharacterTable = new List<TMP_SpriteCharacter>();
  37. public List<TMP_SpriteGlyph> spriteGlyphTable
  38. {
  39. get { return m_SpriteGlyphTable; }
  40. internal set { m_SpriteGlyphTable = value; }
  41. }
  42. [SerializeField]
  43. private List<TMP_SpriteGlyph> m_SpriteGlyphTable = new List<TMP_SpriteGlyph>();
  44. // List which contains the SpriteInfo for the sprites contained in the sprite sheet.
  45. public List<TMP_Sprite> spriteInfoList;
  46. /// <summary>
  47. /// Dictionary used to lookup the index of a given sprite based on a Unicode value.
  48. /// </summary>
  49. //private Dictionary<int, int> m_SpriteUnicodeLookup;
  50. /// <summary>
  51. /// List which contains the Fallback font assets for this font.
  52. /// </summary>
  53. [SerializeField]
  54. public List<TMP_SpriteAsset> fallbackSpriteAssets;
  55. internal bool m_IsSpriteAssetLookupTablesDirty = false;
  56. void Awake()
  57. {
  58. // Check version number of sprite asset to see if it needs to be upgraded.
  59. if (this.material != null && string.IsNullOrEmpty(m_Version))
  60. UpgradeSpriteAsset();
  61. }
  62. #if UNITY_EDITOR
  63. /// <summary>
  64. ///
  65. /// </summary>
  66. void OnValidate()
  67. {
  68. //Debug.Log("Sprite Asset [" + name + "] has changed.");
  69. //UpdateLookupTables();
  70. //TMPro_EventManager.ON_SPRITE_ASSET_PROPERTY_CHANGED(true, this);
  71. }
  72. #endif
  73. /// <summary>
  74. /// Create a material for the sprite asset.
  75. /// </summary>
  76. /// <returns></returns>
  77. Material GetDefaultSpriteMaterial()
  78. {
  79. //isEditingAsset = true;
  80. ShaderUtilities.GetShaderPropertyIDs();
  81. // Add a new material
  82. Shader shader = Shader.Find("TextMeshPro/Sprite");
  83. Material tempMaterial = new Material(shader);
  84. tempMaterial.SetTexture(ShaderUtilities.ID_MainTex, spriteSheet);
  85. tempMaterial.hideFlags = HideFlags.HideInHierarchy;
  86. #if UNITY_EDITOR
  87. UnityEditor.AssetDatabase.AddObjectToAsset(tempMaterial, this);
  88. UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(this));
  89. #endif
  90. //isEditingAsset = false;
  91. return tempMaterial;
  92. }
  93. /// <summary>
  94. /// Function to update the sprite name and unicode lookup tables.
  95. /// This function should be called when a sprite's name or unicode value changes or when a new sprite is added.
  96. /// </summary>
  97. public void UpdateLookupTables()
  98. {
  99. //Debug.Log("Updating [" + this.name + "] Lookup tables.");
  100. // Check version number of sprite asset to see if it needs to be upgraded.
  101. if (this.material != null && string.IsNullOrEmpty(m_Version))
  102. UpgradeSpriteAsset();
  103. // Initialize / Clear glyph index lookup dictionary.
  104. if (m_GlyphIndexLookup == null)
  105. m_GlyphIndexLookup = new Dictionary<uint, int>();
  106. else
  107. m_GlyphIndexLookup.Clear();
  108. for (int i = 0; i < m_SpriteGlyphTable.Count; i++)
  109. {
  110. uint glyphIndex = m_SpriteGlyphTable[i].index;
  111. if (m_GlyphIndexLookup.ContainsKey(glyphIndex) == false)
  112. m_GlyphIndexLookup.Add(glyphIndex, i);
  113. }
  114. if (m_NameLookup == null)
  115. m_NameLookup = new Dictionary<int, int>();
  116. else
  117. m_NameLookup.Clear();
  118. if (m_UnicodeLookup == null)
  119. m_UnicodeLookup = new Dictionary<uint, int>();
  120. else
  121. m_UnicodeLookup.Clear();
  122. for (int i = 0; i < m_SpriteCharacterTable.Count; i++)
  123. {
  124. int nameHashCode = m_SpriteCharacterTable[i].hashCode;
  125. if (m_NameLookup.ContainsKey(nameHashCode) == false)
  126. m_NameLookup.Add(nameHashCode, i);
  127. uint unicode = m_SpriteCharacterTable[i].unicode;
  128. if (m_UnicodeLookup.ContainsKey(unicode) == false)
  129. m_UnicodeLookup.Add(unicode, i);
  130. // Update glyph reference which is not serialized
  131. uint glyphIndex = m_SpriteCharacterTable[i].glyphIndex;
  132. if (m_GlyphIndexLookup.TryGetValue(glyphIndex, out int index))
  133. m_SpriteCharacterTable[i].glyph = m_SpriteGlyphTable[index];
  134. }
  135. m_IsSpriteAssetLookupTablesDirty = false;
  136. }
  137. /// <summary>
  138. /// Function which returns the sprite index using the hashcode of the name
  139. /// </summary>
  140. /// <param name="hashCode"></param>
  141. /// <returns></returns>
  142. public int GetSpriteIndexFromHashcode(int hashCode)
  143. {
  144. if (m_NameLookup == null)
  145. UpdateLookupTables();
  146. if (m_NameLookup.TryGetValue(hashCode, out int index))
  147. return index;
  148. return -1;
  149. }
  150. /// <summary>
  151. /// Returns the index of the sprite for the given unicode value.
  152. /// </summary>
  153. /// <param name="unicode"></param>
  154. /// <returns></returns>
  155. public int GetSpriteIndexFromUnicode (uint unicode)
  156. {
  157. if (m_UnicodeLookup == null)
  158. UpdateLookupTables();
  159. if (m_UnicodeLookup.TryGetValue(unicode, out int index))
  160. return index;
  161. return -1;
  162. }
  163. /// <summary>
  164. /// Returns the index of the sprite for the given name.
  165. /// </summary>
  166. /// <param name="name"></param>
  167. /// <returns></returns>
  168. public int GetSpriteIndexFromName (string name)
  169. {
  170. if (m_NameLookup == null)
  171. UpdateLookupTables();
  172. int hashCode = TMP_TextUtilities.GetSimpleHashCode(name);
  173. return GetSpriteIndexFromHashcode(hashCode);
  174. }
  175. /// <summary>
  176. /// Used to keep track of which Sprite Assets have been searched.
  177. /// </summary>
  178. private static List<int> k_searchedSpriteAssets;
  179. /// <summary>
  180. /// Search through the given sprite asset and its fallbacks for the specified sprite matching the given unicode character.
  181. /// </summary>
  182. /// <param name="spriteAsset">The font asset to search for the given character.</param>
  183. /// <param name="unicode">The character to find.</param>
  184. /// <param name="glyph">out parameter containing the glyph for the specified character (if found).</param>
  185. /// <returns></returns>
  186. public static TMP_SpriteAsset SearchForSpriteByUnicode(TMP_SpriteAsset spriteAsset, uint unicode, bool includeFallbacks, out int spriteIndex)
  187. {
  188. // Check to make sure sprite asset is not null
  189. if (spriteAsset == null) { spriteIndex = -1; return null; }
  190. // Get sprite index for the given unicode
  191. spriteIndex = spriteAsset.GetSpriteIndexFromUnicode(unicode);
  192. if (spriteIndex != -1)
  193. return spriteAsset;
  194. // Initialize list to track instance of Sprite Assets that have already been searched.
  195. if (k_searchedSpriteAssets == null)
  196. k_searchedSpriteAssets = new List<int>();
  197. k_searchedSpriteAssets.Clear();
  198. // Get instance ID of sprite asset and add to list.
  199. int id = spriteAsset.GetInstanceID();
  200. k_searchedSpriteAssets.Add(id);
  201. // Search potential fallback sprite assets if includeFallbacks is true.
  202. if (includeFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  203. return SearchForSpriteByUnicodeInternal(spriteAsset.fallbackSpriteAssets, unicode, includeFallbacks, out spriteIndex);
  204. // Search default sprite asset potentially assigned in the TMP Settings.
  205. if (includeFallbacks && TMP_Settings.defaultSpriteAsset != null)
  206. return SearchForSpriteByUnicodeInternal(TMP_Settings.defaultSpriteAsset, unicode, includeFallbacks, out spriteIndex);
  207. spriteIndex = -1;
  208. return null;
  209. }
  210. /// <summary>
  211. /// Search through the given list of sprite assets and fallbacks for a sprite whose unicode value matches the target unicode.
  212. /// </summary>
  213. /// <param name="spriteAssets"></param>
  214. /// <param name="unicode"></param>
  215. /// <param name="includeFallbacks"></param>
  216. /// <param name="spriteIndex"></param>
  217. /// <returns></returns>
  218. private static TMP_SpriteAsset SearchForSpriteByUnicodeInternal(List<TMP_SpriteAsset> spriteAssets, uint unicode, bool includeFallbacks, out int spriteIndex)
  219. {
  220. for (int i = 0; i < spriteAssets.Count; i++)
  221. {
  222. TMP_SpriteAsset temp = spriteAssets[i];
  223. if (temp == null) continue;
  224. int id = temp.GetInstanceID();
  225. // Skip over the fallback sprite asset if it has already been searched.
  226. if (k_searchedSpriteAssets.Contains(id)) continue;
  227. // Add to list of font assets already searched.
  228. k_searchedSpriteAssets.Add(id);
  229. temp = SearchForSpriteByUnicodeInternal(temp, unicode, includeFallbacks, out spriteIndex);
  230. if (temp != null)
  231. return temp;
  232. }
  233. spriteIndex = -1;
  234. return null;
  235. }
  236. /// <summary>
  237. /// Search the given sprite asset and fallbacks for a sprite whose unicode value matches the target unicode.
  238. /// </summary>
  239. /// <param name="spriteAsset"></param>
  240. /// <param name="unicode"></param>
  241. /// <param name="includeFallbacks"></param>
  242. /// <param name="spriteIndex"></param>
  243. /// <returns></returns>
  244. private static TMP_SpriteAsset SearchForSpriteByUnicodeInternal(TMP_SpriteAsset spriteAsset, uint unicode, bool includeFallbacks, out int spriteIndex)
  245. {
  246. // Get sprite index for the given unicode
  247. spriteIndex = spriteAsset.GetSpriteIndexFromUnicode(unicode);
  248. if (spriteIndex != -1)
  249. return spriteAsset;
  250. if (includeFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  251. return SearchForSpriteByUnicodeInternal(spriteAsset.fallbackSpriteAssets, unicode, includeFallbacks, out spriteIndex);
  252. spriteIndex = -1;
  253. return null;
  254. }
  255. /// <summary>
  256. /// Search the given sprite asset and fallbacks for a sprite whose hash code value of its name matches the target hash code.
  257. /// </summary>
  258. /// <param name="spriteAsset">The Sprite Asset to search for the given sprite whose name matches the hashcode value</param>
  259. /// <param name="hashCode">The hash code value matching the name of the sprite</param>
  260. /// <param name="includeFallbacks">Include fallback sprite assets in the search</param>
  261. /// <param name="spriteIndex">The index of the sprite matching the provided hash code</param>
  262. /// <returns>The Sprite Asset that contains the sprite</returns>
  263. public static TMP_SpriteAsset SearchForSpriteByHashCode(TMP_SpriteAsset spriteAsset, int hashCode, bool includeFallbacks, out int spriteIndex)
  264. {
  265. // Make sure sprite asset is not null
  266. if (spriteAsset == null) { spriteIndex = -1; return null; }
  267. spriteIndex = spriteAsset.GetSpriteIndexFromHashcode(hashCode);
  268. if (spriteIndex != -1)
  269. return spriteAsset;
  270. // Initialize list to track instance of Sprite Assets that have already been searched.
  271. if (k_searchedSpriteAssets == null)
  272. k_searchedSpriteAssets = new List<int>();
  273. k_searchedSpriteAssets.Clear();
  274. int id = spriteAsset.GetInstanceID();
  275. // Add to list of font assets already searched.
  276. k_searchedSpriteAssets.Add(id);
  277. if (includeFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  278. return SearchForSpriteByHashCodeInternal(spriteAsset.fallbackSpriteAssets, hashCode, includeFallbacks, out spriteIndex);
  279. // Search default sprite asset potentially assigned in the TMP Settings.
  280. if (includeFallbacks && TMP_Settings.defaultSpriteAsset != null)
  281. return SearchForSpriteByHashCodeInternal(TMP_Settings.defaultSpriteAsset, hashCode, includeFallbacks, out spriteIndex);
  282. spriteIndex = -1;
  283. return null;
  284. }
  285. /// <summary>
  286. /// Search through the given list of sprite assets and fallbacks for a sprite whose hash code value of its name matches the target hash code.
  287. /// </summary>
  288. /// <param name="spriteAssets"></param>
  289. /// <param name="hashCode"></param>
  290. /// <param name="searchFallbacks"></param>
  291. /// <param name="spriteIndex"></param>
  292. /// <returns></returns>
  293. private static TMP_SpriteAsset SearchForSpriteByHashCodeInternal(List<TMP_SpriteAsset> spriteAssets, int hashCode, bool searchFallbacks, out int spriteIndex)
  294. {
  295. // Search through the list of sprite assets
  296. for (int i = 0; i < spriteAssets.Count; i++)
  297. {
  298. TMP_SpriteAsset temp = spriteAssets[i];
  299. if (temp == null) continue;
  300. int id = temp.GetInstanceID();
  301. // Skip over the fallback sprite asset if it has already been searched.
  302. if (k_searchedSpriteAssets.Contains(id)) continue;
  303. // Add to list of font assets already searched.
  304. k_searchedSpriteAssets.Add(id);
  305. temp = SearchForSpriteByHashCodeInternal(temp, hashCode, searchFallbacks, out spriteIndex);
  306. if (temp != null)
  307. return temp;
  308. }
  309. spriteIndex = -1;
  310. return null;
  311. }
  312. /// <summary>
  313. /// Search through the given sprite asset and fallbacks for a sprite whose hash code value of its name matches the target hash code.
  314. /// </summary>
  315. /// <param name="spriteAsset"></param>
  316. /// <param name="hashCode"></param>
  317. /// <param name="searchFallbacks"></param>
  318. /// <param name="spriteIndex"></param>
  319. /// <returns></returns>
  320. private static TMP_SpriteAsset SearchForSpriteByHashCodeInternal(TMP_SpriteAsset spriteAsset, int hashCode, bool searchFallbacks, out int spriteIndex)
  321. {
  322. // Get the sprite for the given hash code.
  323. spriteIndex = spriteAsset.GetSpriteIndexFromHashcode(hashCode);
  324. if (spriteIndex != -1)
  325. return spriteAsset;
  326. if (searchFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  327. return SearchForSpriteByHashCodeInternal(spriteAsset.fallbackSpriteAssets, hashCode, searchFallbacks, out spriteIndex);
  328. spriteIndex = -1;
  329. return null;
  330. }
  331. /// <summary>
  332. /// Sort the sprite glyph table by glyph index.
  333. /// </summary>
  334. public void SortGlyphTable()
  335. {
  336. if (m_SpriteGlyphTable == null || m_SpriteGlyphTable.Count == 0) return;
  337. m_SpriteGlyphTable = m_SpriteGlyphTable.OrderBy(item => item.index).ToList();
  338. }
  339. /// <summary>
  340. /// Sort the sprite character table by Unicode values.
  341. /// </summary>
  342. internal void SortCharacterTable()
  343. {
  344. if (m_SpriteCharacterTable != null && m_SpriteCharacterTable.Count > 0)
  345. m_SpriteCharacterTable = m_SpriteCharacterTable.OrderBy(c => c.unicode).ToList();
  346. }
  347. /// <summary>
  348. /// Sort both sprite glyph and character tables.
  349. /// </summary>
  350. internal void SortGlyphAndCharacterTables()
  351. {
  352. SortGlyphTable();
  353. SortCharacterTable();
  354. }
  355. /// <summary>
  356. /// Internal method used to upgrade sprite asset.
  357. /// </summary>
  358. private void UpgradeSpriteAsset()
  359. {
  360. m_Version = "1.1.0";
  361. Debug.Log("Upgrading sprite asset [" + this.name + "] to version " + m_Version + ".", this);
  362. // Convert legacy glyph and character tables to new format
  363. m_SpriteCharacterTable.Clear();
  364. m_SpriteGlyphTable.Clear();
  365. for (int i = 0; i < spriteInfoList.Count; i++)
  366. {
  367. TMP_Sprite oldSprite = spriteInfoList[i];
  368. TMP_SpriteGlyph spriteGlyph = new TMP_SpriteGlyph();
  369. spriteGlyph.index = (uint)i;
  370. spriteGlyph.sprite = oldSprite.sprite;
  371. spriteGlyph.metrics = new GlyphMetrics(oldSprite.width, oldSprite.height, oldSprite.xOffset, oldSprite.yOffset, oldSprite.xAdvance);
  372. spriteGlyph.glyphRect = new GlyphRect((int)oldSprite.x, (int)oldSprite.y, (int)oldSprite.width, (int)oldSprite.height);
  373. spriteGlyph.scale = 1.0f;
  374. spriteGlyph.atlasIndex = 0;
  375. m_SpriteGlyphTable.Add(spriteGlyph);
  376. TMP_SpriteCharacter spriteCharacter = new TMP_SpriteCharacter((uint)oldSprite.unicode, spriteGlyph);
  377. spriteCharacter.name = oldSprite.name;
  378. spriteCharacter.scale = oldSprite.scale;
  379. m_SpriteCharacterTable.Add(spriteCharacter);
  380. }
  381. // Clear legacy glyph info list.
  382. //spriteInfoList.Clear();
  383. UpdateLookupTables();
  384. #if UNITY_EDITOR
  385. UnityEditor.EditorUtility.SetDirty(this);
  386. UnityEditor.AssetDatabase.SaveAssets();
  387. #endif
  388. }
  389. }
  390. }