TMP_SpriteAsset.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  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. int index;
  133. if (m_GlyphIndexLookup.TryGetValue(glyphIndex, out index))
  134. m_SpriteCharacterTable[i].glyph = m_SpriteGlyphTable[index];
  135. }
  136. m_IsSpriteAssetLookupTablesDirty = false;
  137. }
  138. /// <summary>
  139. /// Function which returns the sprite index using the hashcode of the name
  140. /// </summary>
  141. /// <param name="hashCode"></param>
  142. /// <returns></returns>
  143. public int GetSpriteIndexFromHashcode(int hashCode)
  144. {
  145. if (m_NameLookup == null)
  146. UpdateLookupTables();
  147. int index;
  148. if (m_NameLookup.TryGetValue(hashCode, out index))
  149. return index;
  150. return -1;
  151. }
  152. /// <summary>
  153. /// Returns the index of the sprite for the given unicode value.
  154. /// </summary>
  155. /// <param name="unicode"></param>
  156. /// <returns></returns>
  157. public int GetSpriteIndexFromUnicode (uint unicode)
  158. {
  159. if (m_UnicodeLookup == null)
  160. UpdateLookupTables();
  161. int index;
  162. if (m_UnicodeLookup.TryGetValue(unicode, out index))
  163. return index;
  164. return -1;
  165. }
  166. /// <summary>
  167. /// Returns the index of the sprite for the given name.
  168. /// </summary>
  169. /// <param name="name"></param>
  170. /// <returns></returns>
  171. public int GetSpriteIndexFromName (string name)
  172. {
  173. if (m_NameLookup == null)
  174. UpdateLookupTables();
  175. int hashCode = TMP_TextUtilities.GetSimpleHashCode(name);
  176. return GetSpriteIndexFromHashcode(hashCode);
  177. }
  178. /// <summary>
  179. /// Used to keep track of which Sprite Assets have been searched.
  180. /// </summary>
  181. private static List<int> k_searchedSpriteAssets;
  182. /// <summary>
  183. /// Search through the given sprite asset and its fallbacks for the specified sprite matching the given unicode character.
  184. /// </summary>
  185. /// <param name="spriteAsset">The font asset to search for the given character.</param>
  186. /// <param name="unicode">The character to find.</param>
  187. /// <param name="glyph">out parameter containing the glyph for the specified character (if found).</param>
  188. /// <returns></returns>
  189. public static TMP_SpriteAsset SearchForSpriteByUnicode(TMP_SpriteAsset spriteAsset, uint unicode, bool includeFallbacks, out int spriteIndex)
  190. {
  191. // Check to make sure sprite asset is not null
  192. if (spriteAsset == null) { spriteIndex = -1; return null; }
  193. // Get sprite index for the given unicode
  194. spriteIndex = spriteAsset.GetSpriteIndexFromUnicode(unicode);
  195. if (spriteIndex != -1)
  196. return spriteAsset;
  197. // Initialize list to track instance of Sprite Assets that have already been searched.
  198. if (k_searchedSpriteAssets == null)
  199. k_searchedSpriteAssets = new List<int>();
  200. k_searchedSpriteAssets.Clear();
  201. // Get instance ID of sprite asset and add to list.
  202. int id = spriteAsset.GetInstanceID();
  203. k_searchedSpriteAssets.Add(id);
  204. // Search potential fallback sprite assets if includeFallbacks is true.
  205. if (includeFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  206. return SearchForSpriteByUnicodeInternal(spriteAsset.fallbackSpriteAssets, unicode, includeFallbacks, out spriteIndex);
  207. // Search default sprite asset potentially assigned in the TMP Settings.
  208. if (includeFallbacks && TMP_Settings.defaultSpriteAsset != null)
  209. return SearchForSpriteByUnicodeInternal(TMP_Settings.defaultSpriteAsset, unicode, includeFallbacks, out spriteIndex);
  210. spriteIndex = -1;
  211. return null;
  212. }
  213. /// <summary>
  214. /// Search through the given list of sprite assets and fallbacks for a sprite whose unicode value matches the target unicode.
  215. /// </summary>
  216. /// <param name="spriteAssets"></param>
  217. /// <param name="unicode"></param>
  218. /// <param name="includeFallbacks"></param>
  219. /// <param name="spriteIndex"></param>
  220. /// <returns></returns>
  221. private static TMP_SpriteAsset SearchForSpriteByUnicodeInternal(List<TMP_SpriteAsset> spriteAssets, uint unicode, bool includeFallbacks, out int spriteIndex)
  222. {
  223. for (int i = 0; i < spriteAssets.Count; i++)
  224. {
  225. TMP_SpriteAsset temp = spriteAssets[i];
  226. if (temp == null) continue;
  227. int id = temp.GetInstanceID();
  228. // Skip over the fallback sprite asset if it has already been searched.
  229. if (k_searchedSpriteAssets.Contains(id)) continue;
  230. // Add to list of font assets already searched.
  231. k_searchedSpriteAssets.Add(id);
  232. temp = SearchForSpriteByUnicodeInternal(temp, unicode, includeFallbacks, out spriteIndex);
  233. if (temp != null)
  234. return temp;
  235. }
  236. spriteIndex = -1;
  237. return null;
  238. }
  239. /// <summary>
  240. /// Search the given sprite asset and fallbacks for a sprite whose unicode value matches the target unicode.
  241. /// </summary>
  242. /// <param name="spriteAsset"></param>
  243. /// <param name="unicode"></param>
  244. /// <param name="includeFallbacks"></param>
  245. /// <param name="spriteIndex"></param>
  246. /// <returns></returns>
  247. private static TMP_SpriteAsset SearchForSpriteByUnicodeInternal(TMP_SpriteAsset spriteAsset, uint unicode, bool includeFallbacks, out int spriteIndex)
  248. {
  249. // Get sprite index for the given unicode
  250. spriteIndex = spriteAsset.GetSpriteIndexFromUnicode(unicode);
  251. if (spriteIndex != -1)
  252. return spriteAsset;
  253. if (includeFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  254. return SearchForSpriteByUnicodeInternal(spriteAsset.fallbackSpriteAssets, unicode, includeFallbacks, out spriteIndex);
  255. spriteIndex = -1;
  256. return null;
  257. }
  258. /// <summary>
  259. /// Search the given sprite asset and fallbacks for a sprite whose hash code value of its name matches the target hash code.
  260. /// </summary>
  261. /// <param name="spriteAsset">The Sprite Asset to search for the given sprite whose name matches the hashcode value</param>
  262. /// <param name="hashCode">The hash code value matching the name of the sprite</param>
  263. /// <param name="includeFallbacks">Include fallback sprite assets in the search</param>
  264. /// <param name="spriteIndex">The index of the sprite matching the provided hash code</param>
  265. /// <returns>The Sprite Asset that contains the sprite</returns>
  266. public static TMP_SpriteAsset SearchForSpriteByHashCode(TMP_SpriteAsset spriteAsset, int hashCode, bool includeFallbacks, out int spriteIndex)
  267. {
  268. // Make sure sprite asset is not null
  269. if (spriteAsset == null) { spriteIndex = -1; return null; }
  270. spriteIndex = spriteAsset.GetSpriteIndexFromHashcode(hashCode);
  271. if (spriteIndex != -1)
  272. return spriteAsset;
  273. // Initialize list to track instance of Sprite Assets that have already been searched.
  274. if (k_searchedSpriteAssets == null)
  275. k_searchedSpriteAssets = new List<int>();
  276. k_searchedSpriteAssets.Clear();
  277. int id = spriteAsset.GetInstanceID();
  278. // Add to list of font assets already searched.
  279. k_searchedSpriteAssets.Add(id);
  280. if (includeFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  281. return SearchForSpriteByHashCodeInternal(spriteAsset.fallbackSpriteAssets, hashCode, includeFallbacks, out spriteIndex);
  282. // Search default sprite asset potentially assigned in the TMP Settings.
  283. if (includeFallbacks && TMP_Settings.defaultSpriteAsset != null)
  284. return SearchForSpriteByHashCodeInternal(TMP_Settings.defaultSpriteAsset, hashCode, includeFallbacks, out spriteIndex);
  285. spriteIndex = -1;
  286. return null;
  287. }
  288. /// <summary>
  289. /// 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.
  290. /// </summary>
  291. /// <param name="spriteAssets"></param>
  292. /// <param name="hashCode"></param>
  293. /// <param name="searchFallbacks"></param>
  294. /// <param name="spriteIndex"></param>
  295. /// <returns></returns>
  296. private static TMP_SpriteAsset SearchForSpriteByHashCodeInternal(List<TMP_SpriteAsset> spriteAssets, int hashCode, bool searchFallbacks, out int spriteIndex)
  297. {
  298. // Search through the list of sprite assets
  299. for (int i = 0; i < spriteAssets.Count; i++)
  300. {
  301. TMP_SpriteAsset temp = spriteAssets[i];
  302. if (temp == null) continue;
  303. int id = temp.GetInstanceID();
  304. // Skip over the fallback sprite asset if it has already been searched.
  305. if (k_searchedSpriteAssets.Contains(id)) continue;
  306. // Add to list of font assets already searched.
  307. k_searchedSpriteAssets.Add(id);
  308. temp = SearchForSpriteByHashCodeInternal(temp, hashCode, searchFallbacks, out spriteIndex);
  309. if (temp != null)
  310. return temp;
  311. }
  312. spriteIndex = -1;
  313. return null;
  314. }
  315. /// <summary>
  316. /// Search through the given sprite asset and fallbacks for a sprite whose hash code value of its name matches the target hash code.
  317. /// </summary>
  318. /// <param name="spriteAsset"></param>
  319. /// <param name="hashCode"></param>
  320. /// <param name="searchFallbacks"></param>
  321. /// <param name="spriteIndex"></param>
  322. /// <returns></returns>
  323. private static TMP_SpriteAsset SearchForSpriteByHashCodeInternal(TMP_SpriteAsset spriteAsset, int hashCode, bool searchFallbacks, out int spriteIndex)
  324. {
  325. // Get the sprite for the given hash code.
  326. spriteIndex = spriteAsset.GetSpriteIndexFromHashcode(hashCode);
  327. if (spriteIndex != -1)
  328. return spriteAsset;
  329. if (searchFallbacks && spriteAsset.fallbackSpriteAssets != null && spriteAsset.fallbackSpriteAssets.Count > 0)
  330. return SearchForSpriteByHashCodeInternal(spriteAsset.fallbackSpriteAssets, hashCode, searchFallbacks, out spriteIndex);
  331. spriteIndex = -1;
  332. return null;
  333. }
  334. /// <summary>
  335. /// Sort the sprite glyph table by glyph index.
  336. /// </summary>
  337. public void SortGlyphTable()
  338. {
  339. if (m_SpriteGlyphTable == null || m_SpriteGlyphTable.Count == 0) return;
  340. m_SpriteGlyphTable = m_SpriteGlyphTable.OrderBy(item => item.index).ToList();
  341. }
  342. /// <summary>
  343. /// Sort the sprite character table by Unicode values.
  344. /// </summary>
  345. internal void SortCharacterTable()
  346. {
  347. if (m_SpriteCharacterTable != null && m_SpriteCharacterTable.Count > 0)
  348. m_SpriteCharacterTable = m_SpriteCharacterTable.OrderBy(c => c.unicode).ToList();
  349. }
  350. /// <summary>
  351. /// Sort both sprite glyph and character tables.
  352. /// </summary>
  353. internal void SortGlyphAndCharacterTables()
  354. {
  355. SortGlyphTable();
  356. SortCharacterTable();
  357. }
  358. /// <summary>
  359. /// Internal method used to upgrade sprite asset.
  360. /// </summary>
  361. private void UpgradeSpriteAsset()
  362. {
  363. m_Version = "1.1.0";
  364. Debug.Log("Upgrading sprite asset [" + this.name + "] to version " + m_Version + ".", this);
  365. // Convert legacy glyph and character tables to new format
  366. m_SpriteCharacterTable.Clear();
  367. m_SpriteGlyphTable.Clear();
  368. for (int i = 0; i < spriteInfoList.Count; i++)
  369. {
  370. TMP_Sprite oldSprite = spriteInfoList[i];
  371. TMP_SpriteGlyph spriteGlyph = new TMP_SpriteGlyph();
  372. spriteGlyph.index = (uint)i;
  373. spriteGlyph.sprite = oldSprite.sprite;
  374. spriteGlyph.metrics = new GlyphMetrics(oldSprite.width, oldSprite.height, oldSprite.xOffset, oldSprite.yOffset, oldSprite.xAdvance);
  375. spriteGlyph.glyphRect = new GlyphRect((int)oldSprite.x, (int)oldSprite.y, (int)oldSprite.width, (int)oldSprite.height);
  376. spriteGlyph.scale = 1.0f;
  377. spriteGlyph.atlasIndex = 0;
  378. m_SpriteGlyphTable.Add(spriteGlyph);
  379. TMP_SpriteCharacter spriteCharacter = new TMP_SpriteCharacter((uint)oldSprite.unicode, spriteGlyph);
  380. spriteCharacter.name = oldSprite.name;
  381. spriteCharacter.scale = oldSprite.scale;
  382. m_SpriteCharacterTable.Add(spriteCharacter);
  383. }
  384. // Clear legacy glyph info list.
  385. //spriteInfoList.Clear();
  386. UpdateLookupTables();
  387. #if UNITY_EDITOR
  388. UnityEditor.EditorUtility.SetDirty(this);
  389. UnityEditor.AssetDatabase.SaveAssets();
  390. #endif
  391. }
  392. }
  393. }