TextMeshProUGUI.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. using UnityEngine;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine.UI;
  6. using UnityEngine.EventSystems;
  7. using UnityEngine.UI.CoroutineTween;
  8. #pragma warning disable 0414 // Disabled a few warnings related to serialized variables not used in this script but used in the editor.
  9. namespace TMPro
  10. {
  11. [DisallowMultipleComponent]
  12. [RequireComponent(typeof(RectTransform))]
  13. [RequireComponent(typeof(CanvasRenderer))]
  14. [AddComponentMenu("UI/TextMeshPro - Text (UI)", 11)]
  15. [ExecuteAlways]
  16. public partial class TextMeshProUGUI : TMP_Text, ILayoutElement
  17. {
  18. /// <summary>
  19. /// Get the material that will be used for rendering.
  20. /// </summary>
  21. public override Material materialForRendering
  22. {
  23. get { return TMP_MaterialManager.GetMaterialForRendering(this, m_sharedMaterial); }
  24. }
  25. /// <summary>
  26. /// Determines if the size of the text container will be adjusted to fit the text object when it is first created.
  27. /// </summary>
  28. public override bool autoSizeTextContainer
  29. {
  30. get { return m_autoSizeTextContainer; }
  31. set { if (m_autoSizeTextContainer == value) return; m_autoSizeTextContainer = value; if (m_autoSizeTextContainer) { CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this); SetLayoutDirty(); } }
  32. }
  33. /// <summary>
  34. /// Reference to the Mesh used by the text object.
  35. /// </summary>
  36. public override Mesh mesh
  37. {
  38. get { return m_mesh; }
  39. }
  40. /// <summary>
  41. /// Reference to the CanvasRenderer used by the text object.
  42. /// </summary>
  43. public new CanvasRenderer canvasRenderer
  44. {
  45. get
  46. {
  47. if (m_canvasRenderer == null) m_canvasRenderer = GetComponent<CanvasRenderer>();
  48. return m_canvasRenderer;
  49. }
  50. }
  51. /// <summary>
  52. /// Anchor dampening prevents the anchor position from being adjusted unless the positional change exceeds about 40% of the width of the underline character. This essentially stabilizes the anchor position.
  53. /// </summary>
  54. //public bool anchorDampening
  55. //{
  56. // get { return m_anchorDampening; }
  57. // set { if (m_anchorDampening != value) { havePropertiesChanged = true; m_anchorDampening = value; /* ScheduleUpdate(); */ } }
  58. //}
  59. private bool m_isRebuildingLayout = false;
  60. //private bool m_isLayoutDirty = false;
  61. /// <summary>
  62. /// Function called by Unity when the horizontal layout needs to be recalculated.
  63. /// </summary>
  64. public void CalculateLayoutInputHorizontal()
  65. {
  66. //Debug.Log("*** CalculateLayoutHorizontal() ***"); // at Frame: " + Time.frameCount); // called on Object ID " + GetInstanceID());
  67. //// Check if object is active
  68. if (!this.gameObject.activeInHierarchy)
  69. return;
  70. if (m_isCalculateSizeRequired || m_rectTransform.hasChanged)
  71. {
  72. m_preferredWidth = GetPreferredWidth();
  73. ComputeMarginSize();
  74. m_isLayoutDirty = true;
  75. }
  76. }
  77. /// <summary>
  78. /// Function called by Unity when the vertical layout needs to be recalculated.
  79. /// </summary>
  80. public void CalculateLayoutInputVertical()
  81. {
  82. //Debug.Log("*** CalculateLayoutInputVertical() ***"); // at Frame: " + Time.frameCount); // called on Object ID " + GetInstanceID());
  83. //// Check if object is active
  84. if (!this.gameObject.activeInHierarchy) // || IsRectTransformDriven == false)
  85. return;
  86. if (m_isCalculateSizeRequired || m_rectTransform.hasChanged)
  87. {
  88. m_preferredHeight = GetPreferredHeight();
  89. ComputeMarginSize();
  90. m_isLayoutDirty = true;
  91. }
  92. m_isCalculateSizeRequired = false;
  93. }
  94. public override void SetVerticesDirty()
  95. {
  96. if (m_verticesAlreadyDirty || this == null || !this.IsActive() || CanvasUpdateRegistry.IsRebuildingGraphics())
  97. return;
  98. m_verticesAlreadyDirty = true;
  99. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild((ICanvasElement)this);
  100. if (m_OnDirtyVertsCallback != null)
  101. m_OnDirtyVertsCallback();
  102. }
  103. /// <summary>
  104. ///
  105. /// </summary>
  106. public override void SetLayoutDirty()
  107. {
  108. m_isPreferredWidthDirty = true;
  109. m_isPreferredHeightDirty = true;
  110. if ( m_layoutAlreadyDirty || this == null || !this.IsActive())
  111. return;
  112. m_layoutAlreadyDirty = true;
  113. LayoutRebuilder.MarkLayoutForRebuild(this.rectTransform);
  114. m_isLayoutDirty = true;
  115. if (m_OnDirtyLayoutCallback != null)
  116. m_OnDirtyLayoutCallback();
  117. }
  118. /// <summary>
  119. ///
  120. /// </summary>
  121. public override void SetMaterialDirty()
  122. {
  123. //Debug.Log("SetMaterialDirty()");
  124. if (this == null || !this.IsActive() || CanvasUpdateRegistry.IsRebuildingGraphics())
  125. return;
  126. m_isMaterialDirty = true;
  127. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild((ICanvasElement)this);
  128. if (m_OnDirtyMaterialCallback != null)
  129. m_OnDirtyMaterialCallback();
  130. }
  131. /// <summary>
  132. ///
  133. /// </summary>
  134. public override void SetAllDirty()
  135. {
  136. m_isInputParsingRequired = true;
  137. SetLayoutDirty();
  138. SetVerticesDirty();
  139. SetMaterialDirty();
  140. }
  141. /// <summary>
  142. ///
  143. /// </summary>
  144. /// <param name="update"></param>
  145. public override void Rebuild(CanvasUpdate update)
  146. {
  147. if (this == null) return;
  148. if (update == CanvasUpdate.Prelayout)
  149. {
  150. if (m_autoSizeTextContainer)
  151. {
  152. m_rectTransform.sizeDelta = GetPreferredValues(Mathf.Infinity, Mathf.Infinity);
  153. }
  154. }
  155. else if (update == CanvasUpdate.PreRender)
  156. {
  157. OnPreRenderCanvas();
  158. m_verticesAlreadyDirty = false;
  159. m_layoutAlreadyDirty = false;
  160. if (!m_isMaterialDirty) return;
  161. UpdateMaterial();
  162. m_isMaterialDirty = false;
  163. }
  164. }
  165. /// <summary>
  166. /// Method to keep the pivot of the sub text objects in sync with the parent pivot.
  167. /// </summary>
  168. private void UpdateSubObjectPivot()
  169. {
  170. if (m_textInfo == null) return;
  171. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  172. {
  173. m_subTextObjects[i].SetPivotDirty();
  174. }
  175. //m_isPivotDirty = false;
  176. }
  177. /// <summary>
  178. ///
  179. /// </summary>
  180. /// <param name="baseMaterial"></param>
  181. /// <returns></returns>
  182. public override Material GetModifiedMaterial(Material baseMaterial)
  183. {
  184. Material mat = baseMaterial;
  185. if (m_ShouldRecalculateStencil)
  186. {
  187. m_stencilID = TMP_MaterialManager.GetStencilID(gameObject);
  188. m_ShouldRecalculateStencil = false;
  189. }
  190. // Release masking material
  191. //if (m_MaskMaterial != null)
  192. // MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  193. if (m_stencilID > 0)
  194. {
  195. mat = TMP_MaterialManager.GetStencilMaterial(baseMaterial, m_stencilID);
  196. if (m_MaskMaterial != null)
  197. TMP_MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  198. m_MaskMaterial = mat;
  199. }
  200. return mat;
  201. }
  202. /// <summary>
  203. ///
  204. /// </summary>
  205. protected override void UpdateMaterial()
  206. {
  207. //Debug.Log("*** UpdateMaterial() ***");
  208. //if (!this.IsActive())
  209. // return;
  210. if (m_sharedMaterial == null) return;
  211. if (m_canvasRenderer == null) m_canvasRenderer = this.canvasRenderer;
  212. m_canvasRenderer.materialCount = 1;
  213. m_canvasRenderer.SetMaterial(materialForRendering, 0);
  214. }
  215. //public override void OnRebuildRequested()
  216. //{
  217. // //Debug.Log("OnRebuildRequested");
  218. // base.OnRebuildRequested();
  219. //}
  220. //public override bool Raycast(Vector2 sp, Camera eventCamera)
  221. //{
  222. // //Debug.Log("Raycast Event. ScreenPoint: " + sp);
  223. // return base.Raycast(sp, eventCamera);
  224. //}
  225. // MASKING RELATED PROPERTIES
  226. /// <summary>
  227. /// Sets the masking offset from the bounds of the object
  228. /// </summary>
  229. public Vector4 maskOffset
  230. {
  231. get { return m_maskOffset; }
  232. set { m_maskOffset = value; UpdateMask(); m_havePropertiesChanged = true; }
  233. }
  234. //public override Material defaultMaterial
  235. //{
  236. // get { Debug.Log("Default Material called."); return m_sharedMaterial; }
  237. //}
  238. //protected override void OnCanvasHierarchyChanged()
  239. //{
  240. // //Debug.Log("OnCanvasHierarchyChanged...");
  241. //}
  242. // IClippable implementation
  243. /// <summary>
  244. /// Method called when the state of a parent changes.
  245. /// </summary>
  246. public override void RecalculateClipping()
  247. {
  248. //Debug.Log("***** RecalculateClipping() *****");
  249. base.RecalculateClipping();
  250. }
  251. // IMaskable Implementation
  252. /// <summary>
  253. /// Method called when Stencil Mask needs to be updated on this element and parents.
  254. /// </summary>
  255. public override void RecalculateMasking()
  256. {
  257. //Debug.Log("***** RecalculateMasking() *****");
  258. this.m_ShouldRecalculateStencil = true;
  259. SetMaterialDirty();
  260. }
  261. /// <summary>
  262. /// Override of the Cull function to provide for the ability to override the culling of the text object.
  263. /// </summary>
  264. /// <param name="clipRect"></param>
  265. /// <param name="validRect"></param>
  266. public override void Cull(Rect clipRect, bool validRect)
  267. {
  268. if (m_ignoreRectMaskCulling) return;
  269. base.Cull(clipRect, validRect);
  270. }
  271. //protected override void UpdateGeometry()
  272. //{
  273. // //Debug.Log("UpdateGeometry");
  274. // //base.UpdateGeometry();
  275. //}
  276. //protected override void UpdateMaterial()
  277. //{
  278. // //Debug.Log("UpdateMaterial called.");
  279. //// base.UpdateMaterial();
  280. //}
  281. /*
  282. /// <summary>
  283. /// Sets the mask type
  284. /// </summary>
  285. public MaskingTypes mask
  286. {
  287. get { return m_mask; }
  288. set { m_mask = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  289. }
  290. /// <summary>
  291. /// Set the masking offset mode (as percentage or pixels)
  292. /// </summary>
  293. public MaskingOffsetMode maskOffsetMode
  294. {
  295. get { return m_maskOffsetMode; }
  296. set { m_maskOffsetMode = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  297. }
  298. */
  299. /*
  300. /// <summary>
  301. /// Sets the softness of the mask
  302. /// </summary>
  303. public Vector2 maskSoftness
  304. {
  305. get { return m_maskSoftness; }
  306. set { m_maskSoftness = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  307. }
  308. /// <summary>
  309. /// Allows to move / offset the mesh vertices by a set amount
  310. /// </summary>
  311. public Vector2 vertexOffset
  312. {
  313. get { return m_vertexOffset; }
  314. set { m_vertexOffset = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  315. }
  316. */
  317. /// <summary>
  318. /// Function to be used to force recomputing of character padding when Shader / Material properties have been changed via script.
  319. /// </summary>
  320. public override void UpdateMeshPadding()
  321. {
  322. m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
  323. m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
  324. m_havePropertiesChanged = true;
  325. checkPaddingRequired = false;
  326. // Return if text object is not awake yet.
  327. if (m_textInfo == null) return;
  328. // Update sub text objects
  329. for (int i = 1; i < m_textInfo.materialCount; i++)
  330. m_subTextObjects[i].UpdateMeshPadding(m_enableExtraPadding, m_isUsingBold);
  331. }
  332. /// <summary>
  333. /// Tweens the CanvasRenderer color associated with this Graphic.
  334. /// </summary>
  335. /// <param name="targetColor">Target color.</param>
  336. /// <param name="duration">Tween duration.</param>
  337. /// <param name="ignoreTimeScale">Should ignore Time.scale?</param>
  338. /// <param name="useAlpha">Should also Tween the alpha channel?</param>
  339. protected override void InternalCrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha)
  340. {
  341. int materialCount = m_textInfo.materialCount;
  342. for (int i = 1; i < materialCount; i++)
  343. {
  344. m_subTextObjects[i].CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha);
  345. }
  346. }
  347. /// <summary>
  348. /// Tweens the alpha of the CanvasRenderer color associated with this Graphic.
  349. /// </summary>
  350. /// <param name="alpha">Target alpha.</param>
  351. /// <param name="duration">Duration of the tween in seconds.</param>
  352. /// <param name="ignoreTimeScale">Should ignore Time.scale?</param>
  353. protected override void InternalCrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale)
  354. {
  355. int materialCount = m_textInfo.materialCount;
  356. for (int i = 1; i < materialCount; i++)
  357. {
  358. m_subTextObjects[i].CrossFadeAlpha(alpha, duration, ignoreTimeScale);
  359. }
  360. }
  361. /// <summary>
  362. /// 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.
  363. /// </summary>
  364. public override void ForceMeshUpdate()
  365. {
  366. //if (m_isEnabled == false) this.OnEnable();
  367. m_havePropertiesChanged = true;
  368. OnPreRenderCanvas();
  369. }
  370. /// <summary>
  371. /// 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.
  372. /// </summary>
  373. /// <param name="ignoreInactive">If set to true, the text object will be regenerated regardless of is active state.</param>
  374. public override void ForceMeshUpdate(bool ignoreInactive)
  375. {
  376. m_havePropertiesChanged = true;
  377. m_ignoreActiveState = true;
  378. OnPreRenderCanvas();
  379. }
  380. /// <summary>
  381. /// Function used to evaluate the length of a text string.
  382. /// </summary>
  383. /// <param name="text"></param>
  384. /// <returns></returns>
  385. public override TMP_TextInfo GetTextInfo(string text)
  386. {
  387. StringToCharArray(text, ref m_TextParsingBuffer);
  388. SetArraySizes(m_TextParsingBuffer);
  389. m_renderMode = TextRenderFlags.DontRender;
  390. ComputeMarginSize();
  391. // Need to make sure we have a valid reference to a Canvas.
  392. if (m_canvas == null) m_canvas = this.canvas;
  393. GenerateTextMesh();
  394. m_renderMode = TextRenderFlags.Render;
  395. return this.textInfo;
  396. }
  397. /// <summary>
  398. /// Function to clear the geometry of the Primary and Sub Text objects.
  399. /// </summary>
  400. public override void ClearMesh()
  401. {
  402. m_canvasRenderer.SetMesh(null);
  403. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  404. m_subTextObjects[i].canvasRenderer.SetMesh(null);
  405. //if (m_linkedTextComponent != null)
  406. // m_linkedTextComponent.ClearMesh();
  407. }
  408. /// <summary>
  409. /// Function to force the regeneration of the text object.
  410. /// </summary>
  411. /// <param name="flags"> Flags to control which portions of the geometry gets uploaded.</param>
  412. //public override void ForceMeshUpdate(TMP_VertexDataUpdateFlags flags) { }
  413. /// <summary>
  414. /// Function to update the geometry of the main and sub text objects.
  415. /// </summary>
  416. /// <param name="mesh"></param>
  417. /// <param name="index"></param>
  418. public override void UpdateGeometry(Mesh mesh, int index)
  419. {
  420. mesh.RecalculateBounds();
  421. if (index == 0)
  422. {
  423. m_canvasRenderer.SetMesh(mesh);
  424. }
  425. else
  426. {
  427. m_subTextObjects[index].canvasRenderer.SetMesh(mesh);
  428. }
  429. }
  430. /// <summary>
  431. /// Function to upload the updated vertex data and renderer.
  432. /// </summary>
  433. public override void UpdateVertexData(TMP_VertexDataUpdateFlags flags)
  434. {
  435. int materialCount = m_textInfo.materialCount;
  436. for (int i = 0; i < materialCount; i++)
  437. {
  438. Mesh mesh;
  439. if (i == 0)
  440. mesh = m_mesh;
  441. else
  442. {
  443. // Clear unused vertices
  444. // TODO: Causes issues when sorting geometry as last vertex data attribute get wiped out.
  445. //m_textInfo.meshInfo[i].ClearUnusedVertices();
  446. mesh = m_subTextObjects[i].mesh;
  447. }
  448. if ((flags & TMP_VertexDataUpdateFlags.Vertices) == TMP_VertexDataUpdateFlags.Vertices)
  449. mesh.vertices = m_textInfo.meshInfo[i].vertices;
  450. if ((flags & TMP_VertexDataUpdateFlags.Uv0) == TMP_VertexDataUpdateFlags.Uv0)
  451. mesh.uv = m_textInfo.meshInfo[i].uvs0;
  452. if ((flags & TMP_VertexDataUpdateFlags.Uv2) == TMP_VertexDataUpdateFlags.Uv2)
  453. mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  454. //if ((flags & TMP_VertexDataUpdateFlags.Uv4) == TMP_VertexDataUpdateFlags.Uv4)
  455. // mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  456. if ((flags & TMP_VertexDataUpdateFlags.Colors32) == TMP_VertexDataUpdateFlags.Colors32)
  457. mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  458. mesh.RecalculateBounds();
  459. if (i == 0)
  460. m_canvasRenderer.SetMesh(mesh);
  461. else
  462. m_subTextObjects[i].canvasRenderer.SetMesh(mesh);
  463. }
  464. }
  465. /// <summary>
  466. /// Function to upload the updated vertex data and renderer.
  467. /// </summary>
  468. public override void UpdateVertexData()
  469. {
  470. int materialCount = m_textInfo.materialCount;
  471. for (int i = 0; i < materialCount; i++)
  472. {
  473. Mesh mesh;
  474. if (i == 0)
  475. mesh = m_mesh;
  476. else
  477. {
  478. // Clear unused vertices
  479. m_textInfo.meshInfo[i].ClearUnusedVertices();
  480. mesh = m_subTextObjects[i].mesh;
  481. }
  482. //mesh.MarkDynamic();
  483. mesh.vertices = m_textInfo.meshInfo[i].vertices;
  484. mesh.uv = m_textInfo.meshInfo[i].uvs0;
  485. mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  486. //mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  487. mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  488. mesh.RecalculateBounds();
  489. if (i == 0)
  490. m_canvasRenderer.SetMesh(mesh);
  491. else
  492. m_subTextObjects[i].canvasRenderer.SetMesh(mesh);
  493. }
  494. }
  495. public void UpdateFontAsset()
  496. {
  497. LoadFontAsset();
  498. }
  499. }
  500. }