TextMeshPro.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. using UnityEngine;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine.UI;
  6. namespace TMPro
  7. {
  8. [DisallowMultipleComponent]
  9. [RequireComponent(typeof(MeshRenderer))]
  10. [RequireComponent(typeof(MeshFilter))]
  11. [AddComponentMenu("Mesh/TextMeshPro - Text")]
  12. [ExecuteAlways]
  13. public partial class TextMeshPro : TMP_Text, ILayoutElement
  14. {
  15. // Public Properties and Serializable Properties
  16. /// <summary>
  17. /// Sets the Renderer's sorting Layer ID
  18. /// </summary>
  19. public int sortingLayerID
  20. {
  21. get { return m_renderer.sortingLayerID; }
  22. set { m_renderer.sortingLayerID = value; }
  23. }
  24. /// <summary>
  25. /// Sets the Renderer's sorting order within the assigned layer.
  26. /// </summary>
  27. public int sortingOrder
  28. {
  29. get { return m_renderer.sortingOrder; }
  30. set { m_renderer.sortingOrder = value; }
  31. }
  32. /// <summary>
  33. /// Determines if the size of the text container will be adjusted to fit the text object when it is first created.
  34. /// </summary>
  35. public override bool autoSizeTextContainer
  36. {
  37. get { return m_autoSizeTextContainer; }
  38. set { if (m_autoSizeTextContainer == value) return; m_autoSizeTextContainer = value; if (m_autoSizeTextContainer) { TMP_UpdateManager.RegisterTextElementForLayoutRebuild(this); SetLayoutDirty(); } }
  39. }
  40. /// <summary>
  41. /// Returns a reference to the Text Container
  42. /// </summary>
  43. [Obsolete("The TextContainer is now obsolete. Use the RectTransform instead.")]
  44. public TextContainer textContainer
  45. {
  46. get
  47. {
  48. return null;
  49. }
  50. }
  51. /// <summary>
  52. /// Returns a reference to the Transform
  53. /// </summary>
  54. public new Transform transform
  55. {
  56. get
  57. {
  58. if (m_transform == null)
  59. m_transform = GetComponent<Transform>();
  60. return m_transform;
  61. }
  62. }
  63. #pragma warning disable 0108
  64. /// <summary>
  65. /// Returns the rendered assigned to the text object.
  66. /// </summary>
  67. public Renderer renderer
  68. {
  69. get
  70. {
  71. if (m_renderer == null)
  72. m_renderer = GetComponent<Renderer>();
  73. return m_renderer;
  74. }
  75. }
  76. /// <summary>
  77. /// Returns the mesh assigned to the text object.
  78. /// </summary>
  79. public override Mesh mesh
  80. {
  81. get
  82. {
  83. if (m_mesh == null)
  84. {
  85. m_mesh = new Mesh();
  86. m_mesh.hideFlags = HideFlags.HideAndDontSave;
  87. this.meshFilter.mesh = m_mesh;
  88. }
  89. return m_mesh;
  90. }
  91. }
  92. /// <summary>
  93. /// Returns the Mesh Filter of the text object.
  94. /// </summary>
  95. public MeshFilter meshFilter
  96. {
  97. get
  98. {
  99. if (m_meshFilter == null)
  100. m_meshFilter = GetComponent<MeshFilter>();
  101. return m_meshFilter;
  102. }
  103. }
  104. // MASKING RELATED PROPERTIES
  105. /// <summary>
  106. /// Sets the mask type
  107. /// </summary>
  108. public MaskingTypes maskType
  109. {
  110. get { return m_maskType; }
  111. set { m_maskType = value; SetMask(m_maskType); }
  112. }
  113. /// <summary>
  114. /// Function used to set the mask type and coordinates in World Space
  115. /// </summary>
  116. /// <param name="type"></param>
  117. /// <param name="maskCoords"></param>
  118. public void SetMask(MaskingTypes type, Vector4 maskCoords)
  119. {
  120. SetMask(type);
  121. SetMaskCoordinates(maskCoords);
  122. }
  123. /// <summary>
  124. /// Function used to set the mask type, coordinates and softness
  125. /// </summary>
  126. /// <param name="type"></param>
  127. /// <param name="maskCoords"></param>
  128. /// <param name="softnessX"></param>
  129. /// <param name="softnessY"></param>
  130. public void SetMask(MaskingTypes type, Vector4 maskCoords, float softnessX, float softnessY)
  131. {
  132. SetMask(type);
  133. SetMaskCoordinates(maskCoords, softnessX, softnessY);
  134. }
  135. /// <summary>
  136. /// Schedule rebuilding of the text geometry.
  137. /// </summary>
  138. public override void SetVerticesDirty()
  139. {
  140. //Debug.Log("SetVerticesDirty()");
  141. if (m_verticesAlreadyDirty || this == null || !this.IsActive())
  142. return;
  143. TMP_UpdateManager.RegisterTextElementForGraphicRebuild(this);
  144. m_verticesAlreadyDirty = true;
  145. }
  146. /// <summary>
  147. ///
  148. /// </summary>
  149. public override void SetLayoutDirty()
  150. {
  151. m_isPreferredWidthDirty = true;
  152. m_isPreferredHeightDirty = true;
  153. if (m_layoutAlreadyDirty || this == null || !this.IsActive())
  154. return;
  155. //TMP_UpdateManager.RegisterTextElementForLayoutRebuild(this);
  156. m_layoutAlreadyDirty = true;
  157. //LayoutRebuilder.MarkLayoutForRebuild(this.rectTransform);
  158. m_isLayoutDirty = true;
  159. }
  160. /// <summary>
  161. /// Schedule updating of the material used by the text object.
  162. /// </summary>
  163. public override void SetMaterialDirty()
  164. {
  165. //Debug.Log("SetMaterialDirty()");
  166. //if (!this.IsActive())
  167. // return;
  168. //m_isMaterialDirty = true;
  169. UpdateMaterial();
  170. //TMP_UpdateManager.RegisterTextElementForGraphicRebuild(this);
  171. }
  172. /// <summary>
  173. ///
  174. /// </summary>
  175. public override void SetAllDirty()
  176. {
  177. m_isInputParsingRequired = true;
  178. SetLayoutDirty();
  179. SetVerticesDirty();
  180. SetMaterialDirty();
  181. }
  182. /// <summary>
  183. ///
  184. /// </summary>
  185. /// <param name="update"></param>
  186. public override void Rebuild(CanvasUpdate update)
  187. {
  188. if (this == null) return;
  189. if (update == CanvasUpdate.Prelayout)
  190. {
  191. if (m_autoSizeTextContainer)
  192. {
  193. m_rectTransform.sizeDelta = GetPreferredValues(Mathf.Infinity, Mathf.Infinity);
  194. }
  195. }
  196. else if (update == CanvasUpdate.PreRender)
  197. {
  198. this.OnPreRenderObject();
  199. m_verticesAlreadyDirty = false;
  200. m_layoutAlreadyDirty = false;
  201. if (!m_isMaterialDirty) return;
  202. UpdateMaterial();
  203. m_isMaterialDirty = false;
  204. }
  205. }
  206. /// <summary>
  207. ///
  208. /// </summary>
  209. protected override void UpdateMaterial()
  210. {
  211. //Debug.Log("*** UpdateMaterial() ***");
  212. //if (!this.IsActive())
  213. // return;
  214. if (m_sharedMaterial == null)
  215. return;
  216. if (m_renderer == null) m_renderer = this.renderer;
  217. // Only update the material if it has changed.
  218. if (m_renderer.sharedMaterial.GetInstanceID() != m_sharedMaterial.GetInstanceID())
  219. m_renderer.sharedMaterial = m_sharedMaterial;
  220. }
  221. /// <summary>
  222. /// Function to be used to force recomputing of character padding when Shader / Material properties have been changed via script.
  223. /// </summary>
  224. public override void UpdateMeshPadding()
  225. {
  226. m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
  227. m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
  228. m_havePropertiesChanged = true;
  229. checkPaddingRequired = false;
  230. // Return if text object is not awake yet.
  231. if (m_textInfo == null) return;
  232. // Update sub text objects
  233. for (int i = 1; i < m_textInfo.materialCount; i++)
  234. m_subTextObjects[i].UpdateMeshPadding(m_enableExtraPadding, m_isUsingBold);
  235. }
  236. /// <summary>
  237. /// Function to force regeneration of the mesh before its normal process time. This is useful when changes to the text object properties need to be applied immediately.
  238. /// </summary>
  239. public override void ForceMeshUpdate()
  240. {
  241. //Debug.Log("ForceMeshUpdate() called.");
  242. m_havePropertiesChanged = true;
  243. OnPreRenderObject();
  244. }
  245. /// <summary>
  246. /// Function to force regeneration of the mesh before its normal process time. This is useful when changes to the text object properties need to be applied immediately.
  247. /// </summary>
  248. /// <param name="ignoreInactive">If set to true, the text object will be regenerated regardless of is active state.</param>
  249. public override void ForceMeshUpdate(bool ignoreInactive)
  250. {
  251. m_havePropertiesChanged = true;
  252. m_ignoreActiveState = true;
  253. OnPreRenderObject();
  254. }
  255. /// <summary>
  256. /// Function used to evaluate the length of a text string.
  257. /// </summary>
  258. /// <param name="text"></param>
  259. /// <returns></returns>
  260. public override TMP_TextInfo GetTextInfo(string text)
  261. {
  262. StringToCharArray(text, ref m_TextParsingBuffer);
  263. SetArraySizes(m_TextParsingBuffer);
  264. m_renderMode = TextRenderFlags.DontRender;
  265. ComputeMarginSize();
  266. GenerateTextMesh();
  267. m_renderMode = TextRenderFlags.Render;
  268. return this.textInfo;
  269. }
  270. /// <summary>
  271. /// Function to clear the geometry of the Primary and Sub Text objects.
  272. /// </summary>
  273. public override void ClearMesh(bool updateMesh)
  274. {
  275. if (m_textInfo.meshInfo[0].mesh == null) m_textInfo.meshInfo[0].mesh = m_mesh;
  276. m_textInfo.ClearMeshInfo(updateMesh);
  277. }
  278. /// <summary>
  279. /// Function to force the regeneration of the text object.
  280. /// </summary>
  281. /// <param name="flags"> Flags to control which portions of the geometry gets uploaded.</param>
  282. //public override void ForceMeshUpdate(TMP_VertexDataUpdateFlags flags) { }
  283. /// <summary>
  284. /// Function to update the geometry of the main and sub text objects.
  285. /// </summary>
  286. /// <param name="mesh"></param>
  287. /// <param name="index"></param>
  288. public override void UpdateGeometry(Mesh mesh, int index)
  289. {
  290. mesh.RecalculateBounds();
  291. }
  292. /// <summary>
  293. /// Function to upload the updated vertex data and renderer.
  294. /// </summary>
  295. public override void UpdateVertexData(TMP_VertexDataUpdateFlags flags)
  296. {
  297. int materialCount = m_textInfo.materialCount;
  298. for (int i = 0; i < materialCount; i++)
  299. {
  300. Mesh mesh;
  301. if (i == 0)
  302. mesh = m_mesh;
  303. else
  304. {
  305. // Clear unused vertices
  306. // TODO: Causes issues when sorting geometry as last vertex data attribute get wiped out.
  307. //m_textInfo.meshInfo[i].ClearUnusedVertices();
  308. mesh = m_subTextObjects[i].mesh;
  309. }
  310. //mesh.MarkDynamic();
  311. if ((flags & TMP_VertexDataUpdateFlags.Vertices) == TMP_VertexDataUpdateFlags.Vertices)
  312. mesh.vertices = m_textInfo.meshInfo[i].vertices;
  313. if ((flags & TMP_VertexDataUpdateFlags.Uv0) == TMP_VertexDataUpdateFlags.Uv0)
  314. mesh.uv = m_textInfo.meshInfo[i].uvs0;
  315. if ((flags & TMP_VertexDataUpdateFlags.Uv2) == TMP_VertexDataUpdateFlags.Uv2)
  316. mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  317. //if ((flags & TMP_VertexDataUpdateFlags.Uv4) == TMP_VertexDataUpdateFlags.Uv4)
  318. // mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  319. if ((flags & TMP_VertexDataUpdateFlags.Colors32) == TMP_VertexDataUpdateFlags.Colors32)
  320. mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  321. mesh.RecalculateBounds();
  322. }
  323. }
  324. /// <summary>
  325. /// Function to upload the updated vertex data and renderer.
  326. /// </summary>
  327. public override void UpdateVertexData()
  328. {
  329. int materialCount = m_textInfo.materialCount;
  330. for (int i = 0; i < materialCount; i++)
  331. {
  332. Mesh mesh;
  333. if (i == 0)
  334. mesh = m_mesh;
  335. else
  336. {
  337. // Clear unused vertices
  338. m_textInfo.meshInfo[i].ClearUnusedVertices();
  339. mesh = m_subTextObjects[i].mesh;
  340. }
  341. //mesh.MarkDynamic();
  342. mesh.vertices = m_textInfo.meshInfo[i].vertices;
  343. mesh.uv = m_textInfo.meshInfo[i].uvs0;
  344. mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  345. //mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  346. mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  347. mesh.RecalculateBounds();
  348. }
  349. }
  350. public void UpdateFontAsset()
  351. {
  352. LoadFontAsset();
  353. }
  354. private bool m_currentAutoSizeMode;
  355. public void CalculateLayoutInputHorizontal()
  356. {
  357. //Debug.Log("*** CalculateLayoutInputHorizontal() ***");
  358. if (!this.gameObject.activeInHierarchy)
  359. return;
  360. //IsRectTransformDriven = true;
  361. m_currentAutoSizeMode = m_enableAutoSizing;
  362. if (m_isCalculateSizeRequired || m_rectTransform.hasChanged)
  363. {
  364. //Debug.Log("Calculating Layout Horizontal");
  365. //m_LayoutPhase = AutoLayoutPhase.Horizontal;
  366. //m_isRebuildingLayout = true;
  367. m_minWidth = 0;
  368. m_flexibleWidth = 0;
  369. //m_renderMode = TextRenderFlags.GetPreferredSizes; // Set Text to not Render and exit early once we have new width values.
  370. if (m_enableAutoSizing)
  371. {
  372. m_fontSize = m_fontSizeMax;
  373. }
  374. // Set Margins to Infinity
  375. m_marginWidth = k_LargePositiveFloat;
  376. m_marginHeight = k_LargePositiveFloat;
  377. if (m_isInputParsingRequired || m_isTextTruncated)
  378. ParseInputText();
  379. GenerateTextMesh();
  380. m_renderMode = TextRenderFlags.Render;
  381. //m_preferredWidth = (int)m_preferredWidth + 1f;
  382. ComputeMarginSize();
  383. //Debug.Log("Preferred Width: " + m_preferredWidth + " Margin Width: " + m_marginWidth + " Preferred Height: " + m_preferredHeight + " Margin Height: " + m_marginHeight + " Rendered Width: " + m_renderedWidth + " Height: " + m_renderedHeight + " RectTransform Width: " + m_rectTransform.rect);
  384. m_isLayoutDirty = true;
  385. }
  386. }
  387. public void CalculateLayoutInputVertical()
  388. {
  389. //Debug.Log("*** CalculateLayoutInputVertical() ***");
  390. // Check if object is active
  391. if (!this.gameObject.activeInHierarchy) // || IsRectTransformDriven == false)
  392. return;
  393. //IsRectTransformDriven = true;
  394. if (m_isCalculateSizeRequired || m_rectTransform.hasChanged)
  395. {
  396. //Debug.Log("Calculating Layout InputVertical");
  397. //m_LayoutPhase = AutoLayoutPhase.Vertical;
  398. //m_isRebuildingLayout = true;
  399. m_minHeight = 0;
  400. m_flexibleHeight = 0;
  401. //m_renderMode = TextRenderFlags.GetPreferredSizes;
  402. if (m_enableAutoSizing)
  403. {
  404. m_currentAutoSizeMode = true;
  405. m_enableAutoSizing = false;
  406. }
  407. m_marginHeight = k_LargePositiveFloat;
  408. GenerateTextMesh();
  409. m_enableAutoSizing = m_currentAutoSizeMode;
  410. m_renderMode = TextRenderFlags.Render;
  411. //m_preferredHeight = (int)m_preferredHeight + 1f;
  412. ComputeMarginSize();
  413. //Debug.Log("Preferred Height: " + m_preferredHeight + " Margin Height: " + m_marginHeight + " Preferred Width: " + m_preferredWidth + " Margin Width: " + m_marginWidth + " Rendered Width: " + m_renderedWidth + " Height: " + m_renderedHeight + " RectTransform Width: " + m_rectTransform.rect);
  414. m_isLayoutDirty = true;
  415. }
  416. m_isCalculateSizeRequired = false;
  417. }
  418. }
  419. }