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.

4247 lines
209 KiB

  1. //#define TMP_PROFILE_ON
  2. //#define TMP_PROFILE_PHASES_ON
  3. using UnityEngine;
  4. using System;
  5. using System.Collections.Generic;
  6. using UnityEngine.UI;
  7. #pragma warning disable 0414 // Disabled a few warnings related to serialized variables not used in this script but used in the editor.
  8. #pragma warning disable 0618 // Disabled warning due to SetVertices being deprecated until new release with SetMesh() is available.
  9. namespace TMPro
  10. {
  11. public partial class TextMeshProUGUI
  12. {
  13. [SerializeField]
  14. private bool m_hasFontAssetChanged = false; // Used to track when font properties have changed.
  15. [SerializeField]
  16. protected TMP_SubMeshUI[] m_subTextObjects = new TMP_SubMeshUI[8];
  17. private float m_previousLossyScaleY = -1; // Used for Tracking lossy scale changes in the transform;
  18. private Vector3[] m_RectTransformCorners = new Vector3[4];
  19. private CanvasRenderer m_canvasRenderer;
  20. private Canvas m_canvas;
  21. private bool m_isFirstAllocation; // Flag to determine if this is the first allocation of the buffers.
  22. private int m_max_characters = 8; // Determines the initial allocation and size of the character array / buffer.
  23. //private int m_max_numberOfLines = 4; // Determines the initial allocation and maximum number of lines of text.
  24. // MASKING RELATED PROPERTIES
  25. private bool m_isMaskingEnabled;
  26. // This property is now obsolete and used for compatibility with previous releases (prior to release 0.1.54).
  27. [SerializeField]
  28. private Material m_baseMaterial;
  29. private bool m_isScrollRegionSet;
  30. //private Mask m_mask;
  31. private int m_stencilID = 0;
  32. [SerializeField]
  33. private Vector4 m_maskOffset;
  34. // Matrix used to animated Env Map
  35. private Matrix4x4 m_EnvMapMatrix = new Matrix4x4();
  36. //private bool m_isEnabled;
  37. [NonSerialized]
  38. private bool m_isRegisteredForEvents;
  39. // DEBUG Variables
  40. //private System.Diagnostics.Stopwatch m_StopWatch;
  41. //private int frame = 0;
  42. //private int m_recursiveCount = 0;
  43. private int m_recursiveCountA = 0;
  44. private int loopCountA = 0;
  45. //private int loopCountB = 0;
  46. //private int loopCountC = 0;
  47. //private int loopCountD = 0;
  48. //private int loopCountE = 0;
  49. //[SerializeField]
  50. //private new Material m_MaskMaterial;
  51. protected override void Awake()
  52. {
  53. //Debug.Log("***** Awake() *****");
  54. #if UNITY_EDITOR
  55. // Special handling for TMP Settings and importing Essential Resources
  56. if (TMP_Settings.instance == null)
  57. {
  58. if (m_isWaitingOnResourceLoad == false)
  59. TMPro_EventManager.RESOURCE_LOAD_EVENT.Add(ON_RESOURCES_LOADED);
  60. m_isWaitingOnResourceLoad = true;
  61. return;
  62. }
  63. #endif
  64. // Cache Reference to the Canvas
  65. m_canvas = this.canvas;
  66. m_isOrthographic = true;
  67. // Cache Reference to RectTransform.
  68. m_rectTransform = gameObject.GetComponent<RectTransform>();
  69. if (m_rectTransform == null)
  70. m_rectTransform = gameObject.AddComponent<RectTransform>();
  71. // Cache a reference to the CanvasRenderer.
  72. m_canvasRenderer = GetComponent<CanvasRenderer>();
  73. if (m_canvasRenderer == null)
  74. m_canvasRenderer = gameObject.AddComponent<CanvasRenderer> ();
  75. if (m_mesh == null)
  76. {
  77. //Debug.Log("Creating new mesh.");
  78. m_mesh = new Mesh();
  79. m_mesh.hideFlags = HideFlags.HideAndDontSave;
  80. //m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0));
  81. }
  82. // Load TMP Settings for new text object instances.
  83. LoadDefaultSettings();
  84. // Load the font asset and assign material to renderer.
  85. LoadFontAsset();
  86. // Load Default TMP StyleSheet
  87. TMP_StyleSheet.LoadDefaultStyleSheet();
  88. // Allocate our initial buffers.
  89. if (m_char_buffer == null)
  90. m_char_buffer = new int[m_max_characters];
  91. m_cached_TextElement = new TMP_Glyph();
  92. m_isFirstAllocation = true;
  93. if (m_textInfo == null)
  94. m_textInfo = new TMP_TextInfo(this);
  95. // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen.
  96. if (m_fontAsset == null)
  97. {
  98. Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this);
  99. return;
  100. }
  101. // Check to make sure Sub Text Objects are tracked correctly in the event a Prefab is used.
  102. TMP_SubMeshUI[] subTextObjects = GetComponentsInChildren<TMP_SubMeshUI>();
  103. if (subTextObjects.Length > 0)
  104. {
  105. for (int i = 0; i < subTextObjects.Length; i++)
  106. m_subTextObjects[i + 1] = subTextObjects[i];
  107. }
  108. // Set flags to ensure our text is parsed and redrawn.
  109. m_isInputParsingRequired = true;
  110. m_havePropertiesChanged = true;
  111. m_isCalculateSizeRequired = true;
  112. m_isAwake = true;
  113. }
  114. protected override void OnEnable()
  115. {
  116. //Debug.Log("*** OnEnable() ***", this);
  117. // Return if Awake() has not been called on the text object.
  118. if (m_isAwake == false)
  119. return;
  120. if (!m_isRegisteredForEvents)
  121. {
  122. //Debug.Log("Registering for Events.");
  123. #if UNITY_EDITOR
  124. // Register Callbacks for various events.
  125. TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Add(ON_MATERIAL_PROPERTY_CHANGED);
  126. TMPro_EventManager.FONT_PROPERTY_EVENT.Add(ON_FONT_PROPERTY_CHANGED);
  127. TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Add(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
  128. TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Add(ON_DRAG_AND_DROP_MATERIAL);
  129. TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Add(ON_TEXT_STYLE_CHANGED);
  130. TMPro_EventManager.COLOR_GRADIENT_PROPERTY_EVENT.Add(ON_COLOR_GRADIENT_CHANGED);
  131. TMPro_EventManager.TMP_SETTINGS_PROPERTY_EVENT.Add(ON_TMP_SETTINGS_CHANGED);
  132. #endif
  133. m_isRegisteredForEvents = true;
  134. }
  135. // Cache Reference to the Canvas
  136. m_canvas = GetCanvas();
  137. SetActiveSubMeshes(true);
  138. // Register Graphic Component to receive event triggers
  139. GraphicRegistry.RegisterGraphicForCanvas(m_canvas, this);
  140. ComputeMarginSize();
  141. m_verticesAlreadyDirty = false;
  142. m_layoutAlreadyDirty = false;
  143. m_ShouldRecalculateStencil = true;
  144. m_isInputParsingRequired = true;
  145. SetAllDirty();
  146. RecalculateClipping();
  147. }
  148. protected override void OnDisable()
  149. {
  150. //base.OnDisable();
  151. //Debug.Log("***** OnDisable() *****"); //for " + this.name + " with ID: " + this.GetInstanceID() + " has been called.");
  152. // Return if Awake() has not been called on the text object.
  153. if (m_isAwake == false)
  154. return;
  155. if (m_MaskMaterial != null)
  156. {
  157. TMP_MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  158. m_MaskMaterial = null;
  159. }
  160. // UnRegister Graphic Component
  161. GraphicRegistry.UnregisterGraphicForCanvas(m_canvas, this);
  162. CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild((ICanvasElement)this);
  163. if (m_canvasRenderer != null)
  164. m_canvasRenderer.Clear();
  165. SetActiveSubMeshes(false);
  166. LayoutRebuilder.MarkLayoutForRebuild(m_rectTransform);
  167. RecalculateClipping();
  168. }
  169. protected override void OnDestroy()
  170. {
  171. //base.OnDestroy();
  172. //Debug.Log("***** OnDestroy() *****");
  173. // UnRegister Graphic Component
  174. GraphicRegistry.UnregisterGraphicForCanvas(m_canvas, this);
  175. // Clean up remaining mesh
  176. if (m_mesh != null)
  177. DestroyImmediate(m_mesh);
  178. // Clean up mask material
  179. if (m_MaskMaterial != null)
  180. {
  181. TMP_MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  182. m_MaskMaterial = null;
  183. }
  184. #if UNITY_EDITOR
  185. // Unregister the event this object was listening to
  186. TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Remove(ON_MATERIAL_PROPERTY_CHANGED);
  187. TMPro_EventManager.FONT_PROPERTY_EVENT.Remove(ON_FONT_PROPERTY_CHANGED);
  188. TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Remove(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
  189. TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Remove(ON_DRAG_AND_DROP_MATERIAL);
  190. TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Remove(ON_TEXT_STYLE_CHANGED);
  191. TMPro_EventManager.COLOR_GRADIENT_PROPERTY_EVENT.Remove(ON_COLOR_GRADIENT_CHANGED);
  192. TMPro_EventManager.TMP_SETTINGS_PROPERTY_EVENT.Remove(ON_TMP_SETTINGS_CHANGED);
  193. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  194. #endif
  195. m_isRegisteredForEvents = false;
  196. }
  197. #if UNITY_EDITOR
  198. protected override void Reset()
  199. {
  200. //Debug.Log("***** Reset() *****"); //has been called.");
  201. // Return if Awake() has not been called on the text object.
  202. if (m_isAwake == false)
  203. return;
  204. LoadDefaultSettings();
  205. LoadFontAsset();
  206. m_isInputParsingRequired = true;
  207. m_havePropertiesChanged = true;
  208. }
  209. protected override void OnValidate()
  210. {
  211. //Debug.Log("***** OnValidate() ***** Frame:" + Time.frameCount); // ID " + GetInstanceID()); // New Material [" + m_sharedMaterial.name + "] with ID " + m_sharedMaterial.GetInstanceID() + ". Base Material is [" + m_baseMaterial.name + "] with ID " + m_baseMaterial.GetInstanceID() + ". Previous Base Material is [" + (m_lastBaseMaterial == null ? "Null" : m_lastBaseMaterial.name) + "].");
  212. // Return if Awake() has not been called on the text object.
  213. if (m_isAwake == false)
  214. return;
  215. // Handle Font Asset changes in the inspector.
  216. if (m_fontAsset == null || m_hasFontAssetChanged)
  217. {
  218. LoadFontAsset();
  219. m_isCalculateSizeRequired = true;
  220. m_hasFontAssetChanged = false;
  221. }
  222. if (m_canvasRenderer == null || m_canvasRenderer.GetMaterial() == null || m_canvasRenderer.GetMaterial().GetTexture(ShaderUtilities.ID_MainTex) == null || m_fontAsset == null || m_fontAsset.atlas.GetInstanceID() != m_canvasRenderer.GetMaterial().GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  223. {
  224. LoadFontAsset();
  225. m_isCalculateSizeRequired = true;
  226. m_hasFontAssetChanged = false;
  227. }
  228. m_padding = GetPaddingForMaterial();
  229. //ComputeMarginSize();
  230. m_isInputParsingRequired = true;
  231. m_inputSource = TextInputSources.Text;
  232. m_havePropertiesChanged = true;
  233. m_isCalculateSizeRequired = true;
  234. m_isPreferredWidthDirty = true;
  235. m_isPreferredHeightDirty = true;
  236. SetAllDirty();
  237. }
  238. // Event received when TMP resources have been loaded.
  239. void ON_RESOURCES_LOADED()
  240. {
  241. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  242. Awake();
  243. OnEnable();
  244. }
  245. // Event received when custom material editor properties are changed.
  246. void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat)
  247. {
  248. //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED event received."); // Targeted Material is: " + mat.name + " m_sharedMaterial: " + m_sharedMaterial.name + " with ID:" + m_sharedMaterial.GetInstanceID() + " m_renderer.sharedMaterial: " + m_canvasRenderer.GetMaterial() + " Masking Material:" + m_MaskMaterial.GetInstanceID());
  249. ShaderUtilities.GetShaderPropertyIDs(); // Initialize ShaderUtilities and get shader property IDs.
  250. int materialID = mat.GetInstanceID();
  251. int sharedMaterialID = m_sharedMaterial.GetInstanceID();
  252. int maskingMaterialID = m_MaskMaterial == null ? 0 : m_MaskMaterial.GetInstanceID();
  253. if (m_canvasRenderer == null || m_canvasRenderer.GetMaterial() == null)
  254. {
  255. if (m_canvasRenderer == null) return;
  256. if (m_fontAsset != null)
  257. {
  258. m_canvasRenderer.SetMaterial(m_fontAsset.material, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  259. //Debug.LogWarning("No Material was assigned to " + name + ". " + m_fontAsset.material.name + " was assigned.");
  260. }
  261. else
  262. Debug.LogWarning("No Font Asset assigned to " + name + ". Please assign a Font Asset.", this);
  263. }
  264. if (m_canvasRenderer.GetMaterial() != m_sharedMaterial && m_fontAsset == null) // || m_renderer.sharedMaterials.Contains(mat))
  265. {
  266. //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED Called on Target ID: " + GetInstanceID() + ". Previous Material:" + m_sharedMaterial + " New Material:" + m_uiRenderer.GetMaterial()); // on Object ID:" + GetInstanceID() + ". m_sharedMaterial: " + m_sharedMaterial.name + " m_renderer.sharedMaterial: " + m_renderer.sharedMaterial.name);
  267. m_sharedMaterial = m_canvasRenderer.GetMaterial();
  268. }
  269. // Make sure material properties are synchronized between the assigned material and masking material.
  270. if (m_MaskMaterial != null)
  271. {
  272. UnityEditor.Undo.RecordObject(m_MaskMaterial, "Material Property Changes");
  273. UnityEditor.Undo.RecordObject(m_sharedMaterial, "Material Property Changes");
  274. if (materialID == sharedMaterialID)
  275. {
  276. //Debug.Log("Copy base material properties to masking material if not null.");
  277. float stencilID = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilID);
  278. float stencilComp = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilComp);
  279. //float stencilOp = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilOp);
  280. //float stencilRead = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilReadMask);
  281. //float stencilWrite = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilWriteMask);
  282. m_MaskMaterial.CopyPropertiesFromMaterial(mat);
  283. m_MaskMaterial.shaderKeywords = mat.shaderKeywords;
  284. m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilID, stencilID);
  285. m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilComp, stencilComp);
  286. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilOp, stencilOp);
  287. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilReadMask, stencilID);
  288. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilWriteMask, 0);
  289. }
  290. else if (materialID == maskingMaterialID)
  291. {
  292. // Update the padding
  293. GetPaddingForMaterial(mat);
  294. m_sharedMaterial.CopyPropertiesFromMaterial(mat);
  295. m_sharedMaterial.shaderKeywords = mat.shaderKeywords;
  296. m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilID, 0);
  297. m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilComp, 8);
  298. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilOp, 0);
  299. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilReadMask, 255);
  300. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilWriteMask, 255);
  301. }
  302. }
  303. m_padding = GetPaddingForMaterial();
  304. m_havePropertiesChanged = true;
  305. SetVerticesDirty();
  306. //SetMaterialDirty();
  307. }
  308. // Event received when font asset properties are changed in Font Inspector
  309. void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font)
  310. {
  311. if (MaterialReference.Contains(m_materialReferences, font))
  312. {
  313. //Debug.Log("ON_FONT_PROPERTY_CHANGED event received.");
  314. m_isInputParsingRequired = true;
  315. m_havePropertiesChanged = true;
  316. SetLayoutDirty();
  317. SetVerticesDirty();
  318. }
  319. }
  320. // Event received when UNDO / REDO Event alters the properties of the object.
  321. void ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED(bool isChanged, TextMeshProUGUI obj)
  322. {
  323. //Debug.Log("Event Received by " + obj);
  324. if (obj == this)
  325. {
  326. //Debug.Log("Undo / Redo Event Received by Object ID:" + GetInstanceID());
  327. m_havePropertiesChanged = true;
  328. m_isInputParsingRequired = true;
  329. ComputeMarginSize();
  330. SetVerticesDirty();
  331. }
  332. }
  333. // Event to Track Material Changed resulting from Drag-n-drop.
  334. void ON_DRAG_AND_DROP_MATERIAL(GameObject obj, Material currentMaterial, Material newMaterial)
  335. {
  336. //Debug.Log("Drag-n-Drop Event - Receiving Object ID " + GetInstanceID() + ". Sender ID " + obj.GetInstanceID()); // + ". Prefab Parent is " + UnityEditor.PrefabUtility.GetPrefabParent(gameObject).GetInstanceID()); // + ". New Material is " + newMaterial.name + " with ID " + newMaterial.GetInstanceID() + ". Base Material is " + m_baseMaterial.name + " with ID " + m_baseMaterial.GetInstanceID());
  337. // Check if event applies to this current object
  338. #if UNITY_2018_2_OR_NEWER
  339. if (obj == gameObject || UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(gameObject) == obj)
  340. #else
  341. if (obj == gameObject || UnityEditor.PrefabUtility.GetPrefabParent(gameObject) == obj)
  342. #endif
  343. {
  344. UnityEditor.Undo.RecordObject(this, "Material Assignment");
  345. UnityEditor.Undo.RecordObject(m_canvasRenderer, "Material Assignment");
  346. m_sharedMaterial = newMaterial;
  347. m_padding = GetPaddingForMaterial();
  348. m_havePropertiesChanged = true;
  349. SetVerticesDirty();
  350. SetMaterialDirty();
  351. }
  352. }
  353. // Event received when Text Styles are changed.
  354. void ON_TEXT_STYLE_CHANGED(bool isChanged)
  355. {
  356. m_havePropertiesChanged = true;
  357. m_isInputParsingRequired = true;
  358. SetVerticesDirty();
  359. }
  360. /// <summary>
  361. /// Event received when a Color Gradient Preset is modified.
  362. /// </summary>
  363. /// <param name="textObject"></param>
  364. void ON_COLOR_GRADIENT_CHANGED(TMP_ColorGradient gradient)
  365. {
  366. if (m_fontColorGradientPreset != null && gradient.GetInstanceID() == m_fontColorGradientPreset.GetInstanceID())
  367. {
  368. m_havePropertiesChanged = true;
  369. SetVerticesDirty();
  370. }
  371. }
  372. /// <summary>
  373. /// Event received when the TMP Settings are changed.
  374. /// </summary>
  375. void ON_TMP_SETTINGS_CHANGED()
  376. {
  377. m_defaultSpriteAsset = null;
  378. m_havePropertiesChanged = true;
  379. m_isInputParsingRequired = true;
  380. SetAllDirty();
  381. }
  382. #endif
  383. // Function which loads either the default font or a newly assigned font asset. This function also assigned the appropriate material to the renderer.
  384. protected override void LoadFontAsset()
  385. {
  386. //Debug.Log("***** LoadFontAsset() *****"); //TextMeshPro LoadFontAsset() has been called."); // Current Font Asset is " + (font != null ? font.name: "Null") );
  387. ShaderUtilities.GetShaderPropertyIDs(); // Initialize & Get shader property IDs.
  388. if (m_fontAsset == null)
  389. {
  390. if (TMP_Settings.defaultFontAsset != null)
  391. m_fontAsset = TMP_Settings.defaultFontAsset;
  392. else
  393. m_fontAsset = Resources.Load<TMP_FontAsset>("Fonts & Materials/LiberationSans SDF");
  394. if (m_fontAsset == null)
  395. {
  396. Debug.LogWarning("The LiberationSans SDF Font Asset was not found. There is no Font Asset assigned to " + gameObject.name + ".", this);
  397. return;
  398. }
  399. if (m_fontAsset.characterDictionary == null)
  400. {
  401. Debug.Log("Dictionary is Null!");
  402. }
  403. m_sharedMaterial = m_fontAsset.material;
  404. }
  405. else
  406. {
  407. // Read font definition if needed.
  408. if (m_fontAsset.characterDictionary == null)
  409. m_fontAsset.ReadFontDefinition();
  410. // Added for compatibility with previous releases.
  411. if (m_sharedMaterial == null && m_baseMaterial != null)
  412. {
  413. m_sharedMaterial = m_baseMaterial;
  414. m_baseMaterial = null;
  415. }
  416. // If font atlas texture doesn't match the assigned material font atlas, switch back to default material specified in the Font Asset.
  417. if (m_sharedMaterial == null || m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex) == null || m_fontAsset.atlas.GetInstanceID() != m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  418. {
  419. if (m_fontAsset.material == null)
  420. Debug.LogWarning("The Font Atlas Texture of the Font Asset " + m_fontAsset.name + " assigned to " + gameObject.name + " is missing.", this);
  421. else
  422. m_sharedMaterial = m_fontAsset.material;
  423. }
  424. }
  425. // Find and cache Underline & Ellipsis characters.
  426. GetSpecialCharacters(m_fontAsset);
  427. m_padding = GetPaddingForMaterial();
  428. SetMaterialDirty();
  429. }
  430. /// <summary>
  431. /// Method to retrieve the parent Canvas.
  432. /// </summary>
  433. private Canvas GetCanvas()
  434. {
  435. Canvas canvas = null;
  436. var list = TMP_ListPool<Canvas>.Get();
  437. gameObject.GetComponentsInParent(false, list);
  438. if (list.Count > 0)
  439. {
  440. // Find the first active and enabled canvas.
  441. for (int i = 0; i < list.Count; ++i)
  442. {
  443. if (list[i].isActiveAndEnabled)
  444. {
  445. canvas = list[i];
  446. break;
  447. }
  448. }
  449. }
  450. TMP_ListPool<Canvas>.Release(list);
  451. return canvas;
  452. }
  453. /// <summary>
  454. /// Method used when animating the Env Map on the material.
  455. /// </summary>
  456. void UpdateEnvMapMatrix()
  457. {
  458. if (!m_sharedMaterial.HasProperty(ShaderUtilities.ID_EnvMap) || m_sharedMaterial.GetTexture(ShaderUtilities.ID_EnvMap) == null)
  459. return;
  460. //Debug.Log("Updating Env Matrix...");
  461. Vector3 rotation = m_sharedMaterial.GetVector(ShaderUtilities.ID_EnvMatrixRotation);
  462. m_EnvMapMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(rotation), Vector3.one);
  463. m_sharedMaterial.SetMatrix(ShaderUtilities.ID_EnvMatrix, m_EnvMapMatrix);
  464. }
  465. // Enable Masking in the Shader
  466. void EnableMasking()
  467. {
  468. if (m_fontMaterial == null)
  469. {
  470. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  471. m_canvasRenderer.SetMaterial(m_fontMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  472. }
  473. m_sharedMaterial = m_fontMaterial;
  474. if (m_sharedMaterial.HasProperty(ShaderUtilities.ID_ClipRect))
  475. {
  476. m_sharedMaterial.EnableKeyword(ShaderUtilities.Keyword_MASK_SOFT);
  477. m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_HARD);
  478. m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_TEX);
  479. UpdateMask(); // Update Masking Coordinates
  480. }
  481. m_isMaskingEnabled = true;
  482. //m_uiRenderer.SetMaterial(m_sharedMaterial, null);
  483. //m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
  484. //m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
  485. /*
  486. Material mat = m_uiRenderer.GetMaterial();
  487. if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
  488. {
  489. mat.EnableKeyword("MASK_SOFT");
  490. mat.DisableKeyword("MASK_HARD");
  491. mat.DisableKeyword("MASK_OFF");
  492. m_isMaskingEnabled = true;
  493. UpdateMask();
  494. }
  495. */
  496. }
  497. // Enable Masking in the Shader
  498. void DisableMasking()
  499. {
  500. if (m_fontMaterial != null)
  501. {
  502. if (m_stencilID > 0)
  503. m_sharedMaterial = m_MaskMaterial;
  504. //else
  505. // m_sharedMaterial = m_baseMaterial;
  506. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  507. DestroyImmediate(m_fontMaterial);
  508. }
  509. m_isMaskingEnabled = false;
  510. /*
  511. if (m_maskingMaterial != null && m_stencilID == 0)
  512. {
  513. m_sharedMaterial = m_baseMaterial;
  514. m_uiRenderer.SetMaterial(m_sharedMaterial, null);
  515. }
  516. else if (m_stencilID > 0)
  517. {
  518. m_sharedMaterial.EnableKeyword("MASK_OFF");
  519. m_sharedMaterial.DisableKeyword("MASK_HARD");
  520. m_sharedMaterial.DisableKeyword("MASK_SOFT");
  521. }
  522. */
  523. /*
  524. Material mat = m_uiRenderer.GetMaterial();
  525. if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
  526. {
  527. mat.EnableKeyword("MASK_OFF");
  528. mat.DisableKeyword("MASK_HARD");
  529. mat.DisableKeyword("MASK_SOFT");
  530. m_isMaskingEnabled = false;
  531. UpdateMask();
  532. }
  533. */
  534. }
  535. // Update & recompute Mask offset
  536. void UpdateMask()
  537. {
  538. //Debug.Log("Updating Mask...");
  539. if (m_rectTransform != null)
  540. {
  541. //Material mat = m_uiRenderer.GetMaterial();
  542. //if (mat == null || (m_overflowMode == TextOverflowModes.ScrollRect && m_isScrollRegionSet))
  543. // return;
  544. if (!ShaderUtilities.isInitialized)
  545. ShaderUtilities.GetShaderPropertyIDs();
  546. //Debug.Log("Setting Mask for the first time.");
  547. m_isScrollRegionSet = true;
  548. float softnessX = Mathf.Min(Mathf.Min(m_margin.x, m_margin.z), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX));
  549. float softnessY = Mathf.Min(Mathf.Min(m_margin.y, m_margin.w), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessY));
  550. softnessX = softnessX > 0 ? softnessX : 0;
  551. softnessY = softnessY > 0 ? softnessY : 0;
  552. float width = (m_rectTransform.rect.width - Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2 + softnessX;
  553. float height = (m_rectTransform.rect.height - Mathf.Max(m_margin.y, 0) - Mathf.Max(m_margin.w, 0)) / 2 + softnessY;
  554. Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-Mathf.Max(m_margin.y, 0) + Mathf.Max(m_margin.w, 0)) / 2);
  555. //Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (margin.x - margin.z) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-margin.y + margin.w) / 2);
  556. Vector4 mask = new Vector4(center.x, center.y, width, height);
  557. //Debug.Log(mask);
  558. //Rect rect = new Rect(0, 0, m_rectTransform.rect.width + margin.x + margin.z, m_rectTransform.rect.height + margin.y + margin.w);
  559. //int softness = (int)m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX) / 2;
  560. m_sharedMaterial.SetVector(ShaderUtilities.ID_ClipRect, mask);
  561. }
  562. }
  563. // Function called internally when a new material is assigned via the fontMaterial property.
  564. protected override Material GetMaterial(Material mat)
  565. {
  566. // Get Shader PropertyIDs if they haven't been cached already.
  567. ShaderUtilities.GetShaderPropertyIDs();
  568. // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
  569. // This can occur when the Duplicate Material Context menu is used on an inactive object.
  570. //if (m_canvasRenderer == null)
  571. // m_canvasRenderer = GetComponent<CanvasRenderer>();
  572. // Create Instance Material only if the new material is not the same instance previously used.
  573. if (m_fontMaterial == null || m_fontMaterial.GetInstanceID() != mat.GetInstanceID())
  574. m_fontMaterial = CreateMaterialInstance(mat);
  575. m_sharedMaterial = m_fontMaterial;
  576. m_padding = GetPaddingForMaterial();
  577. m_ShouldRecalculateStencil = true;
  578. SetVerticesDirty();
  579. SetMaterialDirty();
  580. return m_sharedMaterial;
  581. }
  582. /// <summary>
  583. /// Method returning instances of the materials used by the text object.
  584. /// </summary>
  585. /// <returns></returns>
  586. protected override Material[] GetMaterials(Material[] mats)
  587. {
  588. int materialCount = m_textInfo.materialCount;
  589. if (m_fontMaterials == null)
  590. m_fontMaterials = new Material[materialCount];
  591. else if (m_fontMaterials.Length != materialCount)
  592. TMP_TextInfo.Resize(ref m_fontMaterials, materialCount, false);
  593. // Get instances of the materials
  594. for (int i = 0; i < materialCount; i++)
  595. {
  596. if (i == 0)
  597. m_fontMaterials[i] = fontMaterial;
  598. else
  599. m_fontMaterials[i] = m_subTextObjects[i].material;
  600. }
  601. m_fontSharedMaterials = m_fontMaterials;
  602. return m_fontMaterials;
  603. }
  604. // Function called internally when a new shared material is assigned via the fontSharedMaterial property.
  605. protected override void SetSharedMaterial(Material mat)
  606. {
  607. // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
  608. // This can occur when the Duplicate Material Context menu is used on an inactive object.
  609. //if (m_canvasRenderer == null)
  610. // m_canvasRenderer = GetComponent<CanvasRenderer>();
  611. m_sharedMaterial = mat;
  612. m_padding = GetPaddingForMaterial();
  613. SetMaterialDirty();
  614. }
  615. /// <summary>
  616. /// Method returning an array containing the materials used by the text object.
  617. /// </summary>
  618. /// <returns></returns>
  619. protected override Material[] GetSharedMaterials()
  620. {
  621. int materialCount = m_textInfo.materialCount;
  622. if (m_fontSharedMaterials == null)
  623. m_fontSharedMaterials = new Material[materialCount];
  624. else if (m_fontSharedMaterials.Length != materialCount)
  625. TMP_TextInfo.Resize(ref m_fontSharedMaterials, materialCount, false);
  626. for (int i = 0; i < materialCount; i++)
  627. {
  628. if (i == 0)
  629. m_fontSharedMaterials[i] = m_sharedMaterial;
  630. else
  631. m_fontSharedMaterials[i] = m_subTextObjects[i].sharedMaterial;
  632. }
  633. return m_fontSharedMaterials;
  634. }
  635. /// <summary>
  636. /// Method used to assign new materials to the text and sub text objects.
  637. /// </summary>
  638. protected override void SetSharedMaterials(Material[] materials)
  639. {
  640. int materialCount = m_textInfo.materialCount;
  641. // Check allocation of the fontSharedMaterials array.
  642. if (m_fontSharedMaterials == null)
  643. m_fontSharedMaterials = new Material[materialCount];
  644. else if (m_fontSharedMaterials.Length != materialCount)
  645. TMP_TextInfo.Resize(ref m_fontSharedMaterials, materialCount, false);
  646. // Only assign as many materials as the text object contains.
  647. for (int i = 0; i < materialCount; i++)
  648. {
  649. if (i == 0)
  650. {
  651. // Only assign new material if the font atlas textures match.
  652. if (materials[i].GetTexture(ShaderUtilities.ID_MainTex) == null || materials[i].GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  653. continue;
  654. m_sharedMaterial = m_fontSharedMaterials[i] = materials[i];
  655. m_padding = GetPaddingForMaterial(m_sharedMaterial);
  656. }
  657. else
  658. {
  659. // Only assign new material if the font atlas textures match.
  660. if (materials[i].GetTexture(ShaderUtilities.ID_MainTex) == null || materials[i].GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_subTextObjects[i].sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  661. continue;
  662. // Only assign a new material if none were specified in the text input.
  663. if (m_subTextObjects[i].isDefaultMaterial)
  664. m_subTextObjects[i].sharedMaterial = m_fontSharedMaterials[i] = materials[i];
  665. }
  666. }
  667. }
  668. // This function will create an instance of the Font Material.
  669. protected override void SetOutlineThickness(float thickness)
  670. {
  671. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  672. if (m_fontMaterial != null && m_sharedMaterial.GetInstanceID() != m_fontMaterial.GetInstanceID())
  673. {
  674. m_sharedMaterial = m_fontMaterial;
  675. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  676. }
  677. else if(m_fontMaterial == null)
  678. {
  679. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  680. m_sharedMaterial = m_fontMaterial;
  681. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  682. }
  683. thickness = Mathf.Clamp01(thickness);
  684. m_sharedMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, thickness);
  685. m_padding = GetPaddingForMaterial();
  686. }
  687. // This function will create an instance of the Font Material.
  688. protected override void SetFaceColor(Color32 color)
  689. {
  690. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  691. if (m_fontMaterial == null)
  692. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  693. m_sharedMaterial = m_fontMaterial;
  694. m_padding = GetPaddingForMaterial();
  695. m_sharedMaterial.SetColor(ShaderUtilities.ID_FaceColor, color);
  696. }
  697. // This function will create an instance of the Font Material.
  698. protected override void SetOutlineColor(Color32 color)
  699. {
  700. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  701. if (m_fontMaterial == null)
  702. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  703. m_sharedMaterial = m_fontMaterial;
  704. m_padding = GetPaddingForMaterial();
  705. m_sharedMaterial.SetColor(ShaderUtilities.ID_OutlineColor, color);
  706. }
  707. // Sets the Render Queue and Ztest mode
  708. protected override void SetShaderDepth()
  709. {
  710. if (m_canvas == null || m_sharedMaterial == null)
  711. return;
  712. if (m_canvas.renderMode == RenderMode.ScreenSpaceOverlay || m_isOverlay)
  713. {
  714. // Should this use an instanced material?
  715. m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_ZTestMode, 0);
  716. }
  717. else
  718. { // TODO: This section needs to be tested.
  719. m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_ZTestMode, 4);
  720. }
  721. }
  722. // Sets the Culling mode of the material
  723. protected override void SetCulling()
  724. {
  725. if (m_isCullingEnabled)
  726. {
  727. Material mat = materialForRendering;
  728. if (mat != null)
  729. mat.SetFloat("_CullMode", 2);
  730. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  731. {
  732. mat = m_subTextObjects[i].materialForRendering;
  733. if (mat != null)
  734. {
  735. mat.SetFloat(ShaderUtilities.ShaderTag_CullMode, 2);
  736. }
  737. }
  738. }
  739. else
  740. {
  741. Material mat = materialForRendering;
  742. if (mat != null)
  743. mat.SetFloat("_CullMode", 0);
  744. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  745. {
  746. mat = m_subTextObjects[i].materialForRendering;
  747. if (mat != null)
  748. {
  749. mat.SetFloat(ShaderUtilities.ShaderTag_CullMode, 0);
  750. }
  751. }
  752. }
  753. }
  754. // Set Perspective Correction Mode based on whether Camera is Orthographic or Perspective
  755. void SetPerspectiveCorrection()
  756. {
  757. if (m_isOrthographic)
  758. m_sharedMaterial.SetFloat(ShaderUtilities.ID_PerspectiveFilter, 0.0f);
  759. else
  760. m_sharedMaterial.SetFloat(ShaderUtilities.ID_PerspectiveFilter, 0.875f);
  761. }
  762. /// <summary>
  763. /// Get the padding value for the currently assigned material.
  764. /// </summary>
  765. /// <returns></returns>
  766. protected override float GetPaddingForMaterial(Material mat)
  767. {
  768. m_padding = ShaderUtilities.GetPadding(mat, m_enableExtraPadding, m_isUsingBold);
  769. m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
  770. m_isSDFShader = mat.HasProperty(ShaderUtilities.ID_WeightNormal);
  771. return m_padding;
  772. }
  773. /// <summary>
  774. /// Get the padding value for the currently assigned material.
  775. /// </summary>
  776. /// <returns></returns>
  777. protected override float GetPaddingForMaterial()
  778. {
  779. ShaderUtilities.GetShaderPropertyIDs();
  780. m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
  781. m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
  782. m_isSDFShader = m_sharedMaterial.HasProperty(ShaderUtilities.ID_WeightNormal);
  783. return m_padding;
  784. }
  785. // Function to allocate the necessary buffers to render the text. This function is called whenever the buffer size needs to be increased.
  786. void SetMeshArrays(int size)
  787. {
  788. m_textInfo.meshInfo[0].ResizeMeshInfo(size);
  789. m_canvasRenderer.SetMesh(m_textInfo.meshInfo[0].mesh);
  790. }
  791. // This function parses through the Char[] to determine how many characters will be visible. It then makes sure the arrays are large enough for all those characters.
  792. protected override int SetArraySizes(int[] chars)
  793. {
  794. //Debug.Log("*** SetArraySizes() on Instance ID (" + GetInstanceID() + ") ***");
  795. #if TMP_PROFILE_ON
  796. Profiler.BeginSample("SetArraySizes");
  797. #endif
  798. int tagEnd = 0;
  799. int spriteCount = 0;
  800. m_totalCharacterCount = 0;
  801. m_isUsingBold = false;
  802. m_isParsingText = false;
  803. tag_NoParsing = false;
  804. m_style = m_fontStyle;
  805. m_fontWeightInternal = (m_style & FontStyles.Bold) == FontStyles.Bold ? 700 : m_fontWeight;
  806. m_fontWeightStack.SetDefault(m_fontWeightInternal);
  807. m_currentFontAsset = m_fontAsset;
  808. m_currentMaterial = m_sharedMaterial;
  809. m_currentMaterialIndex = 0;
  810. m_materialReferenceStack.SetDefault(new MaterialReference(m_currentMaterialIndex, m_currentFontAsset, null, m_currentMaterial, m_padding));
  811. m_materialReferenceIndexLookup.Clear();
  812. MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  813. if (m_textInfo == null) m_textInfo = new TMP_TextInfo();
  814. m_textElementType = TMP_TextElementType.Character;
  815. // Clear Linked Text object if we have one.
  816. if (m_linkedTextComponent != null)
  817. {
  818. m_linkedTextComponent.text = string.Empty; // SetText(string.Empty, false);
  819. m_linkedTextComponent.ForceMeshUpdate();
  820. }
  821. // Parsing XML tags in the text
  822. for (int i = 0; i < chars.Length && chars[i] != 0; i++)
  823. {
  824. //Make sure the characterInfo array can hold the next text element.
  825. if (m_textInfo.characterInfo == null || m_totalCharacterCount >= m_textInfo.characterInfo.Length)
  826. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, m_totalCharacterCount + 1, true);
  827. int c = chars[i];
  828. // PARSE XML TAGS
  829. #region PARSE XML TAGS
  830. if (m_isRichText && c == 60) // if Char '<'
  831. {
  832. int prev_MaterialIndex = m_currentMaterialIndex;
  833. // Check if Tag is Valid
  834. if (ValidateHtmlTag(chars, i + 1, out tagEnd))
  835. {
  836. i = tagEnd;
  837. if ((m_style & FontStyles.Bold) == FontStyles.Bold) m_isUsingBold = true;
  838. if (m_textElementType == TMP_TextElementType.Sprite)
  839. {
  840. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  841. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)(57344 + m_spriteIndex);
  842. m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = m_spriteIndex;
  843. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  844. m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = m_currentSpriteAsset;
  845. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  846. m_textInfo.characterInfo[m_totalCharacterCount].elementType = m_textElementType;
  847. // Restore element type and material index to previous values.
  848. m_textElementType = TMP_TextElementType.Character;
  849. m_currentMaterialIndex = prev_MaterialIndex;
  850. spriteCount += 1;
  851. m_totalCharacterCount += 1;
  852. }
  853. continue;
  854. }
  855. }
  856. #endregion
  857. bool isUsingFallback = false;
  858. bool isUsingAlternativeTypeface = false;
  859. TMP_Glyph glyph;
  860. TMP_FontAsset tempFontAsset;
  861. TMP_FontAsset prev_fontAsset = m_currentFontAsset;
  862. Material prev_material = m_currentMaterial;
  863. int prev_materialIndex = m_currentMaterialIndex;
  864. // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
  865. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
  866. if (m_textElementType == TMP_TextElementType.Character)
  867. {
  868. if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase)
  869. {
  870. // If this character is lowercase, switch to uppercase.
  871. if (char.IsLower((char)c))
  872. c = char.ToUpper((char)c);
  873. }
  874. else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase)
  875. {
  876. // If this character is uppercase, switch to lowercase.
  877. if (char.IsUpper((char)c))
  878. c = char.ToLower((char)c);
  879. }
  880. else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps)
  881. {
  882. // Only convert lowercase characters to uppercase.
  883. if (char.IsLower((char)c))
  884. c = char.ToUpper((char)c);
  885. }
  886. }
  887. #endregion
  888. // Handling of font weights.
  889. #region HANDLING OF FONT WEIGHT
  890. tempFontAsset = GetFontAssetForWeight(m_fontWeightInternal);
  891. if (tempFontAsset != null)
  892. {
  893. isUsingFallback = true;
  894. isUsingAlternativeTypeface = true;
  895. m_currentFontAsset = tempFontAsset;
  896. //m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  897. }
  898. #endregion
  899. // Lookup the Glyph data for each character and cache it.
  900. #region LOOKUP GLYPH
  901. tempFontAsset = TMP_FontUtilities.SearchForGlyph(m_currentFontAsset, c, out glyph);
  902. // Search for the glyph in the Sprite Asset assigned to the text object.
  903. if (glyph == null)
  904. {
  905. TMP_SpriteAsset spriteAsset = this.spriteAsset;
  906. if (spriteAsset != null)
  907. {
  908. int spriteIndex = -1;
  909. // Check Default Sprite Asset and its Fallbacks
  910. spriteAsset = TMP_SpriteAsset.SearchForSpriteByUnicode(spriteAsset, c, true, out spriteIndex);
  911. if (spriteIndex != -1)
  912. {
  913. m_textElementType = TMP_TextElementType.Sprite;
  914. m_textInfo.characterInfo[m_totalCharacterCount].elementType = m_textElementType;
  915. m_currentMaterialIndex = MaterialReference.AddMaterialReference(spriteAsset.material, spriteAsset, m_materialReferences, m_materialReferenceIndexLookup);
  916. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  917. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)c;
  918. m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = spriteIndex;
  919. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  920. m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = spriteAsset;
  921. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  922. // Restore element type and material index to previous values.
  923. m_textElementType = TMP_TextElementType.Character;
  924. m_currentMaterialIndex = prev_materialIndex;
  925. spriteCount += 1;
  926. m_totalCharacterCount += 1;
  927. continue;
  928. }
  929. }
  930. }
  931. // Search for the glyph in the list of fallback assigned in the TMP Settings (General Fallbacks).
  932. if (glyph == null)
  933. {
  934. if (TMP_Settings.fallbackFontAssets != null && TMP_Settings.fallbackFontAssets.Count > 0)
  935. tempFontAsset = TMP_FontUtilities.SearchForGlyph(TMP_Settings.fallbackFontAssets, c, out glyph);
  936. }
  937. // Search for the glyph in the Default Font Asset assigned in the TMP Settings file.
  938. if (glyph == null)
  939. {
  940. if (TMP_Settings.defaultFontAsset != null)
  941. tempFontAsset = TMP_FontUtilities.SearchForGlyph(TMP_Settings.defaultFontAsset, c, out glyph);
  942. }
  943. // TODO: Add support for using Sprite Assets like a special Emoji only Sprite Asset when UTF16 or UTF32 glyphs are requested.
  944. // This would kind of mirror native Emoji support.
  945. if (glyph == null)
  946. {
  947. TMP_SpriteAsset spriteAsset = TMP_Settings.defaultSpriteAsset;
  948. if (spriteAsset != null)
  949. {
  950. int spriteIndex = -1;
  951. // Check Default Sprite Asset and its Fallbacks
  952. spriteAsset = TMP_SpriteAsset.SearchForSpriteByUnicode(spriteAsset, c, true, out spriteIndex);
  953. if (spriteIndex != -1)
  954. {
  955. m_textElementType = TMP_TextElementType.Sprite;
  956. m_textInfo.characterInfo[m_totalCharacterCount].elementType = m_textElementType;
  957. m_currentMaterialIndex = MaterialReference.AddMaterialReference(spriteAsset.material, spriteAsset, m_materialReferences, m_materialReferenceIndexLookup);
  958. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  959. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)c;
  960. m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = spriteIndex;
  961. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  962. m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = spriteAsset;
  963. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  964. // Restore element type and material index to previous values.
  965. m_textElementType = TMP_TextElementType.Character;
  966. m_currentMaterialIndex = prev_materialIndex;
  967. spriteCount += 1;
  968. m_totalCharacterCount += 1;
  969. continue;
  970. }
  971. }
  972. }
  973. //Check if Lowercase or Uppercase variant of the character is available.
  974. // Not sure this is necessary anyone as it is very unlikely with recursive search through fallback fonts.
  975. //if (glyph == null)
  976. //{
  977. // if (char.IsLower((char)c))
  978. // {
  979. // if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToUpper((char)c), out glyph))
  980. // c = chars[i] = char.ToUpper((char)c);
  981. // }
  982. // else if (char.IsUpper((char)c))
  983. // {
  984. // if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToLower((char)c), out glyph))
  985. // c = chars[i] = char.ToLower((char)c);
  986. // }
  987. //}
  988. // Replace missing glyph by the Square (9633) glyph or possibly the Space (32) glyph.
  989. if (glyph == null)
  990. {
  991. // Save the original unicode character
  992. int srcGlyph = c;
  993. // Try replacing the missing glyph character by TMP Settings Missing Glyph or Square (9633) character.
  994. c = chars[i] = TMP_Settings.missingGlyphCharacter == 0 ? 9633 : TMP_Settings.missingGlyphCharacter;
  995. // Check for the missing glyph character in the currently assigned font asset.
  996. tempFontAsset = TMP_FontUtilities.SearchForGlyph(m_currentFontAsset, c, out glyph);
  997. if (glyph == null)
  998. {
  999. // Search for the missing glyph character in the TMP Settings Fallback list.
  1000. if (TMP_Settings.fallbackFontAssets != null && TMP_Settings.fallbackFontAssets.Count > 0)
  1001. tempFontAsset = TMP_FontUtilities.SearchForGlyph(TMP_Settings.fallbackFontAssets, c, out glyph);
  1002. }
  1003. if (glyph == null)
  1004. {
  1005. // Search for the missing glyph in the TMP Settings Default Font Asset.
  1006. if (TMP_Settings.defaultFontAsset != null)
  1007. tempFontAsset = TMP_FontUtilities.SearchForGlyph(TMP_Settings.defaultFontAsset, c, out glyph);
  1008. }
  1009. if (glyph == null)
  1010. {
  1011. // Use Space (32) Glyph from the currently assigned font asset.
  1012. c = chars[i] = 32;
  1013. tempFontAsset = TMP_FontUtilities.SearchForGlyph(m_currentFontAsset, c, out glyph);
  1014. if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Character with ASCII value of " + srcGlyph + " was not found in the Font Asset Glyph Table. It was replaced by a space.", this);
  1015. }
  1016. }
  1017. // Determine if the font asset is still the current font asset or a fallback.
  1018. if (tempFontAsset != null)
  1019. {
  1020. if (tempFontAsset.GetInstanceID() != m_currentFontAsset.GetInstanceID())
  1021. {
  1022. isUsingFallback = true;
  1023. isUsingAlternativeTypeface = false;
  1024. m_currentFontAsset = tempFontAsset;
  1025. }
  1026. }
  1027. #endregion
  1028. m_textInfo.characterInfo[m_totalCharacterCount].elementType = TMP_TextElementType.Character;
  1029. m_textInfo.characterInfo[m_totalCharacterCount].textElement = glyph;
  1030. m_textInfo.characterInfo[m_totalCharacterCount].isUsingAlternateTypeface = isUsingAlternativeTypeface;
  1031. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)c;
  1032. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  1033. if (isUsingFallback)
  1034. {
  1035. // Create Fallback material instance matching current material preset if necessary
  1036. if (TMP_Settings.matchMaterialPreset)
  1037. m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material);
  1038. else
  1039. m_currentMaterial = m_currentFontAsset.material;
  1040. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  1041. }
  1042. if (!char.IsWhiteSpace((char)c) && c != 0x200B)
  1043. {
  1044. // Limit the mesh of the main text object to 65535 vertices and use sub objects for the overflow.
  1045. if (m_materialReferences[m_currentMaterialIndex].referenceCount < 16383)
  1046. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1047. else
  1048. {
  1049. m_currentMaterialIndex = MaterialReference.AddMaterialReference(new Material(m_currentMaterial), m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  1050. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1051. }
  1052. }
  1053. m_textInfo.characterInfo[m_totalCharacterCount].material = m_currentMaterial;
  1054. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  1055. m_materialReferences[m_currentMaterialIndex].isFallbackMaterial = isUsingFallback;
  1056. // Restore previous font asset and material if fallback font was used.
  1057. if (isUsingFallback)
  1058. {
  1059. m_materialReferences[m_currentMaterialIndex].fallbackMaterial = prev_material;
  1060. m_currentFontAsset = prev_fontAsset;
  1061. m_currentMaterial = prev_material;
  1062. m_currentMaterialIndex = prev_materialIndex;
  1063. }
  1064. m_totalCharacterCount += 1;
  1065. }
  1066. // Early return if we are calculating the preferred values.
  1067. if (m_isCalculatingPreferredValues)
  1068. {
  1069. m_isCalculatingPreferredValues = false;
  1070. m_isInputParsingRequired = true;
  1071. return m_totalCharacterCount;
  1072. }
  1073. // Save material and sprite count.
  1074. m_textInfo.spriteCount = spriteCount;
  1075. int materialCount = m_textInfo.materialCount = m_materialReferenceIndexLookup.Count;
  1076. // Check if we need to resize the MeshInfo array for handling different materials.
  1077. if (materialCount > m_textInfo.meshInfo.Length)
  1078. TMP_TextInfo.Resize(ref m_textInfo.meshInfo, materialCount, false);
  1079. // Resize SubTextObject array if necessary
  1080. if (materialCount > m_subTextObjects.Length)
  1081. TMP_TextInfo.Resize(ref m_subTextObjects, Mathf.NextPowerOfTwo(materialCount + 1));
  1082. // Resize CharacterInfo[] if allocations are excessive
  1083. if (m_textInfo.characterInfo.Length - m_totalCharacterCount > 256)
  1084. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, Mathf.Max(m_totalCharacterCount + 1, 256), true);
  1085. // Iterate through the material references to set the mesh buffer allocations
  1086. for (int i = 0; i < materialCount; i++)
  1087. {
  1088. // Add new sub text object for each material reference
  1089. if (i > 0)
  1090. {
  1091. if (m_subTextObjects[i] == null)
  1092. {
  1093. m_subTextObjects[i] = TMP_SubMeshUI.AddSubTextObject(this, m_materialReferences[i]);
  1094. // Not sure this is necessary
  1095. m_textInfo.meshInfo[i].vertices = null;
  1096. }
  1097. //else if (m_subTextObjects[i].gameObject.activeInHierarchy == false)
  1098. // m_subTextObjects[i].gameObject.SetActive(true);
  1099. // Make sure the pivots are synchronized
  1100. if (m_rectTransform.pivot != m_subTextObjects[i].rectTransform.pivot)
  1101. m_subTextObjects[i].rectTransform.pivot = m_rectTransform.pivot;
  1102. // Check if the material has changed.
  1103. if (m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.GetInstanceID() != m_materialReferences[i].material.GetInstanceID())
  1104. {
  1105. bool isDefaultMaterial = m_materialReferences[i].isDefaultMaterial;
  1106. m_subTextObjects[i].isDefaultMaterial = isDefaultMaterial;
  1107. // Assign new material if we are not using the default material or if the font asset has changed.
  1108. if (!isDefaultMaterial || m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_materialReferences[i].material.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  1109. {
  1110. m_subTextObjects[i].sharedMaterial = m_materialReferences[i].material;
  1111. m_subTextObjects[i].fontAsset = m_materialReferences[i].fontAsset;
  1112. m_subTextObjects[i].spriteAsset = m_materialReferences[i].spriteAsset;
  1113. }
  1114. }
  1115. // Check if we need to use a Fallback Material
  1116. if (m_materialReferences[i].isFallbackMaterial)
  1117. {
  1118. m_subTextObjects[i].fallbackMaterial = m_materialReferences[i].material;
  1119. m_subTextObjects[i].fallbackSourceMaterial = m_materialReferences[i].fallbackMaterial;
  1120. }
  1121. }
  1122. int referenceCount = m_materialReferences[i].referenceCount;
  1123. // Check to make sure our buffers allocations can accommodate the required text elements.
  1124. if (m_textInfo.meshInfo[i].vertices == null || m_textInfo.meshInfo[i].vertices.Length < referenceCount * 4)
  1125. {
  1126. if (m_textInfo.meshInfo[i].vertices == null)
  1127. {
  1128. if (i == 0)
  1129. m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_mesh, referenceCount + 1);
  1130. else
  1131. m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_subTextObjects[i].mesh, referenceCount + 1);
  1132. }
  1133. else
  1134. m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.NextPowerOfTwo(referenceCount));
  1135. }
  1136. else if (m_textInfo.meshInfo[i].vertices.Length - referenceCount * 4 > 1024)
  1137. {
  1138. // Resize vertex buffers if allocations are excessive.
  1139. //Debug.Log("Reducing the size of the vertex buffers.");
  1140. m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.Max(Mathf.NextPowerOfTwo(referenceCount), 256));
  1141. }
  1142. }
  1143. //TMP_MaterialManager.CleanupFallbackMaterials();
  1144. // Clean up unused SubMeshes
  1145. for (int i = materialCount; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  1146. {
  1147. if (i < m_textInfo.meshInfo.Length)
  1148. {
  1149. m_subTextObjects[i].canvasRenderer.SetMesh(null);
  1150. // TODO: Figure out a way to handle this without running into Unity's Rebuild loop issue.
  1151. //m_subTextObjects[i].gameObject.SetActive(false);
  1152. }
  1153. }
  1154. #if TMP_PROFILE_ON
  1155. Profiler.EndSample();
  1156. #endif
  1157. return m_totalCharacterCount;
  1158. }
  1159. // Added to sort handle the potential issue with OnWillRenderObject() not getting called when objects are not visible by camera.
  1160. //void OnBecameInvisible()
  1161. //{
  1162. // if (m_mesh != null)
  1163. // m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0));
  1164. //}
  1165. /// <summary>
  1166. /// Update the margin width and height
  1167. /// </summary>
  1168. public override void ComputeMarginSize()
  1169. {
  1170. if (this.rectTransform != null)
  1171. {
  1172. //Debug.Log("*** ComputeMarginSize() *** Current RectTransform's Width is " + m_rectTransform.rect.width + " and Height is " + m_rectTransform.rect.height); // + " and size delta is " + m_rectTransform.sizeDelta);
  1173. m_marginWidth = m_rectTransform.rect.width - m_margin.x - m_margin.z;
  1174. m_marginHeight = m_rectTransform.rect.height - m_margin.y - m_margin.w;
  1175. // Update the corners of the RectTransform
  1176. m_RectTransformCorners = GetTextContainerLocalCorners();
  1177. }
  1178. }
  1179. /// <summary>
  1180. ///
  1181. /// </summary>
  1182. protected override void OnDidApplyAnimationProperties()
  1183. {
  1184. m_havePropertiesChanged = true;
  1185. SetVerticesDirty();
  1186. SetLayoutDirty();
  1187. //Debug.Log("Animation Properties have changed.");
  1188. }
  1189. protected override void OnCanvasHierarchyChanged()
  1190. {
  1191. base.OnCanvasHierarchyChanged();
  1192. m_canvas = this.canvas;
  1193. }
  1194. protected override void OnTransformParentChanged()
  1195. {
  1196. //Debug.Log("***** OnTransformParentChanged *****");
  1197. base.OnTransformParentChanged();
  1198. m_canvas = this.canvas;
  1199. ComputeMarginSize();
  1200. m_havePropertiesChanged = true;
  1201. }
  1202. protected override void OnRectTransformDimensionsChange()
  1203. {
  1204. //Debug.Log("*** OnRectTransformDimensionsChange() *** ActiveInHierarchy: " + this.gameObject.activeInHierarchy + " Frame: " + Time.frameCount);
  1205. // Make sure object is active in Hierarchy
  1206. if (!this.gameObject.activeInHierarchy)
  1207. return;
  1208. ComputeMarginSize();
  1209. UpdateSubObjectPivot();
  1210. SetVerticesDirty();
  1211. SetLayoutDirty();
  1212. }
  1213. /// <summary>
  1214. /// Unity standard function used to check if the transform or scale of the text object has changed.
  1215. /// </summary>
  1216. void LateUpdate()
  1217. {
  1218. if (m_rectTransform.hasChanged)
  1219. {
  1220. // We need to update the SDF scale or possibly regenerate the text object if lossy scale has changed.
  1221. float lossyScaleY = m_rectTransform.lossyScale.y;
  1222. if (!m_havePropertiesChanged && lossyScaleY != m_previousLossyScaleY && m_text != string.Empty && m_text != null)
  1223. {
  1224. UpdateSDFScale(lossyScaleY);
  1225. m_previousLossyScaleY = lossyScaleY;
  1226. }
  1227. m_rectTransform.hasChanged = false;
  1228. }
  1229. // Added to handle legacy animation mode.
  1230. if (m_isUsingLegacyAnimationComponent)
  1231. {
  1232. //if (m_havePropertiesChanged)
  1233. m_havePropertiesChanged = true;
  1234. OnPreRenderCanvas();
  1235. }
  1236. }
  1237. // Called just before the Canvas is rendered.
  1238. void OnPreRenderCanvas()
  1239. {
  1240. //Debug.Log("*** OnPreRenderCanvas() *** Frame: " + Time.frameCount);
  1241. // Make sure object is active and that we have a valid Canvas.
  1242. if (!m_isAwake || (this.IsActive() == false && m_ignoreActiveState == false)) return;
  1243. if (m_canvas == null) { m_canvas = this.canvas; if (m_canvas == null) return; }
  1244. // Debug Variables
  1245. loopCountA = 0;
  1246. //loopCountB = 0;
  1247. //loopCountC = 0;
  1248. //loopCountD = 0;
  1249. //loopCountE = 0;
  1250. // Update Margins
  1251. //ComputeMarginSize();
  1252. // Update Mask
  1253. // if (m_isMaskingEnabled)
  1254. // {
  1255. // UpdateMask();
  1256. // }
  1257. if (m_havePropertiesChanged || m_isLayoutDirty)
  1258. {
  1259. //Debug.Log("Properties have changed!"); // Assigned Material is:" + m_sharedMaterial); // New Text is: " + m_text + ".");
  1260. // Update mesh padding if necessary.
  1261. if (checkPaddingRequired)
  1262. UpdateMeshPadding();
  1263. // Reparse the text if the input has changed or text was truncated.
  1264. if (m_isInputParsingRequired || m_isTextTruncated)
  1265. ParseInputText();
  1266. // Reset Font min / max used with Auto-sizing
  1267. if (m_enableAutoSizing)
  1268. m_fontSize = Mathf.Clamp(m_fontSizeBase, m_fontSizeMin, m_fontSizeMax);
  1269. m_maxFontSize = m_fontSizeMax;
  1270. m_minFontSize = m_fontSizeMin;
  1271. m_lineSpacingDelta = 0;
  1272. m_charWidthAdjDelta = 0;
  1273. //m_recursiveCount = 0;
  1274. m_isCharacterWrappingEnabled = false;
  1275. m_isTextTruncated = false;
  1276. m_havePropertiesChanged = false;
  1277. m_isLayoutDirty = false;
  1278. m_ignoreActiveState = false;
  1279. GenerateTextMesh();
  1280. }
  1281. }
  1282. /// <summary>
  1283. /// This is the main function that is responsible for creating / displaying the text.
  1284. /// </summary>
  1285. protected override void GenerateTextMesh()
  1286. {
  1287. //Debug.Log("*** GenerateTextMesh() ***"); // ***** Frame: " + Time.frameCount); // + ". Point Size: " + m_fontSize + ". Margins are (W) " + m_marginWidth + " (H) " + m_marginHeight); // ". Iteration Count: " + loopCountA + ". Min: " + m_minFontSize + " Max: " + m_maxFontSize + " Delta: " + (m_maxFontSize - m_minFontSize) + " Font size is " + m_fontSize); //called for Object with ID " + GetInstanceID()); // Assigned Material is " + m_uiRenderer.GetMaterial().name); // IncludeForMasking " + this.m_IncludeForMasking); // and text is " + m_text);
  1288. //Profiler.BeginSample("TMP Generate Text - Pre");
  1289. // Early exit if no font asset was assigned. This should not be needed since LiberationSans SDF will be assigned by default.
  1290. if (m_fontAsset == null || m_fontAsset.characterDictionary == null)
  1291. {
  1292. Debug.LogWarning("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());
  1293. return;
  1294. }
  1295. // Clear TextInfo
  1296. if (m_textInfo != null)
  1297. m_textInfo.Clear();
  1298. // Early exit if we don't have any Text to generate.
  1299. if (m_char_buffer == null || m_char_buffer.Length == 0 || m_char_buffer[0] == (char)0)
  1300. {
  1301. // Clear mesh and upload changes to the mesh.
  1302. ClearMesh();
  1303. m_preferredWidth = 0;
  1304. m_preferredHeight = 0;
  1305. // Event indicating the text has been regenerated.
  1306. TMPro_EventManager.ON_TEXT_CHANGED(this);
  1307. return;
  1308. }
  1309. m_currentFontAsset = m_fontAsset;
  1310. m_currentMaterial = m_sharedMaterial;
  1311. m_currentMaterialIndex = 0;
  1312. m_materialReferenceStack.SetDefault(new MaterialReference(m_currentMaterialIndex, m_currentFontAsset, null, m_currentMaterial, m_padding));
  1313. m_currentSpriteAsset = m_spriteAsset;
  1314. // Stop all Sprite Animations
  1315. if (m_spriteAnimator != null)
  1316. m_spriteAnimator.StopAllAnimations();
  1317. // Total character count is computed when the text is parsed.
  1318. int totalCharacterCount = m_totalCharacterCount;
  1319. // Calculate the scale of the font based on selected font size and sampling point size.
  1320. // baseScale is calculated using the font asset assigned to the text object.
  1321. float baseScale = m_fontScale = (m_fontSize / m_fontAsset.fontInfo.PointSize * m_fontAsset.fontInfo.Scale);
  1322. float currentElementScale = baseScale;
  1323. m_fontScaleMultiplier = 1;
  1324. m_currentFontSize = m_fontSize;
  1325. m_sizeStack.SetDefault(m_currentFontSize);
  1326. float fontSizeDelta = 0;
  1327. int charCode = 0; // Holds the character code of the currently being processed character.
  1328. m_style = m_fontStyle; // Set the default style.
  1329. m_fontWeightInternal = (m_style & FontStyles.Bold) == FontStyles.Bold ? 700 : m_fontWeight;
  1330. m_fontWeightStack.SetDefault(m_fontWeightInternal);
  1331. m_fontStyleStack.Clear();
  1332. m_lineJustification = m_textAlignment; // Sets the line justification mode to match editor alignment.
  1333. m_lineJustificationStack.SetDefault(m_lineJustification);
  1334. float padding = 0;
  1335. float style_padding = 0; // Extra padding required to accommodate Bold style.
  1336. float bold_xAdvance_multiplier = 1; // Used to increase spacing between character when style is bold.
  1337. m_baselineOffset = 0; // Used by subscript characters.
  1338. m_baselineOffsetStack.Clear();
  1339. // Underline
  1340. bool beginUnderline = false;
  1341. Vector3 underline_start = Vector3.zero; // Used to track where underline starts & ends.
  1342. Vector3 underline_end = Vector3.zero;
  1343. // Strike-through
  1344. bool beginStrikethrough = false;
  1345. Vector3 strikethrough_start = Vector3.zero;
  1346. Vector3 strikethrough_end = Vector3.zero;
  1347. // Text Highlight
  1348. bool beginHighlight = false;
  1349. Vector3 highlight_start = Vector3.zero;
  1350. Vector3 highlight_end = Vector3.zero;
  1351. m_fontColor32 = m_fontColor;
  1352. Color32 vertexColor;
  1353. m_htmlColor = m_fontColor32;
  1354. m_underlineColor = m_htmlColor;
  1355. m_strikethroughColor = m_htmlColor;
  1356. m_colorStack.SetDefault(m_htmlColor);
  1357. m_underlineColorStack.SetDefault(m_htmlColor);
  1358. m_strikethroughColorStack.SetDefault(m_htmlColor);
  1359. m_highlightColorStack.SetDefault(m_htmlColor);
  1360. m_colorGradientPreset = null;
  1361. m_colorGradientStack.SetDefault(null);
  1362. // Clear the Style stack.
  1363. //m_styleStack.Clear();
  1364. // Clear the Action stack.
  1365. m_actionStack.Clear();
  1366. m_isFXMatrixSet = false;
  1367. m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
  1368. m_lineHeight = TMP_Math.FLOAT_UNSET;
  1369. float lineGap = m_currentFontAsset.fontInfo.LineHeight - (m_currentFontAsset.fontInfo.Ascender - m_currentFontAsset.fontInfo.Descender);
  1370. m_cSpacing = 0; // Amount of space added between characters as a result of the use of the <cspace> tag.
  1371. m_monoSpacing = 0;
  1372. float lineOffsetDelta = 0;
  1373. m_xAdvance = 0; // Used to track the position of each character.
  1374. tag_LineIndent = 0; // Used for indentation of text.
  1375. tag_Indent = 0;
  1376. m_indentStack.SetDefault(0);
  1377. tag_NoParsing = false;
  1378. //m_isIgnoringAlignment = false;
  1379. m_characterCount = 0; // Total characters in the char[]
  1380. // Tracking of line information
  1381. m_firstCharacterOfLine = 0;
  1382. m_lastCharacterOfLine = 0;
  1383. m_firstVisibleCharacterOfLine = 0;
  1384. m_lastVisibleCharacterOfLine = 0;
  1385. m_maxLineAscender = k_LargeNegativeFloat;
  1386. m_maxLineDescender = k_LargePositiveFloat;
  1387. m_lineNumber = 0;
  1388. m_lineVisibleCharacterCount = 0;
  1389. bool isStartOfNewLine = true;
  1390. m_firstOverflowCharacterIndex = -1;
  1391. m_pageNumber = 0;
  1392. int pageToDisplay = Mathf.Clamp(m_pageToDisplay - 1, 0, m_textInfo.pageInfo.Length - 1);
  1393. int previousPageOverflowChar = 0;
  1394. int ellipsisIndex = 0;
  1395. Vector4 margins = m_margin;
  1396. float marginWidth = m_marginWidth;
  1397. float marginHeight = m_marginHeight;
  1398. m_marginLeft = 0;
  1399. m_marginRight = 0;
  1400. m_width = -1;
  1401. float width = marginWidth + 0.0001f - m_marginLeft - m_marginRight;
  1402. // Need to initialize these Extents structures
  1403. m_meshExtents.min = k_LargePositiveVector2;
  1404. m_meshExtents.max = k_LargeNegativeVector2;
  1405. // Initialize lineInfo
  1406. m_textInfo.ClearLineInfo();
  1407. // Tracking of the highest Ascender
  1408. m_maxCapHeight = 0;
  1409. m_maxAscender = 0;
  1410. m_maxDescender = 0;
  1411. float pageAscender = 0;
  1412. float maxVisibleDescender = 0;
  1413. bool isMaxVisibleDescenderSet = false;
  1414. m_isNewPage = false;
  1415. // Initialize struct to track states of word wrapping
  1416. bool isFirstWord = true;
  1417. m_isNonBreakingSpace = false;
  1418. bool ignoreNonBreakingSpace = false;
  1419. bool isLastBreakingChar = false;
  1420. float linebreakingWidth = 0;
  1421. int wrappingIndex = 0;
  1422. // Save character and line state before we begin layout.
  1423. SaveWordWrappingState(ref m_SavedWordWrapState, -1, -1);
  1424. SaveWordWrappingState(ref m_SavedLineState, -1, -1);
  1425. loopCountA += 1;
  1426. //Profiler.EndSample();
  1427. #if TMP_PROFILE_PHASES_ON
  1428. Profiler.BeginSample("TMP Generate Text - Phase I");
  1429. #endif
  1430. int endTagIndex = 0;
  1431. // Parse through Character buffer to read HTML tags and begin creating mesh.
  1432. for (int i = 0; i < m_char_buffer.Length && m_char_buffer[i] != 0; i++)
  1433. {
  1434. charCode = m_char_buffer[i];
  1435. // Parse Rich Text Tag
  1436. #region Parse Rich Text Tag
  1437. if (m_isRichText && charCode == 60) // '<'
  1438. {
  1439. m_isParsingText = true;
  1440. m_textElementType = TMP_TextElementType.Character;
  1441. // Check if Tag is valid. If valid, skip to the end of the validated tag.
  1442. if (ValidateHtmlTag(m_char_buffer, i + 1, out endTagIndex))
  1443. {
  1444. i = endTagIndex;
  1445. // Continue to next character or handle the sprite element
  1446. if (m_textElementType == TMP_TextElementType.Character)
  1447. continue;
  1448. }
  1449. }
  1450. else
  1451. {
  1452. m_textElementType = m_textInfo.characterInfo[m_characterCount].elementType;
  1453. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  1454. m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  1455. //m_currentFontAsset = m_materialReferences[m_currentMaterialIndex].fontAsset;
  1456. }
  1457. #endregion End Parse Rich Text Tag
  1458. int prev_MaterialIndex = m_currentMaterialIndex;
  1459. bool isUsingAltTypeface = m_textInfo.characterInfo[m_characterCount].isUsingAlternateTypeface;
  1460. m_isParsingText = false;
  1461. // When using Linked text, mark character as ignored and skip to next character.
  1462. if (m_characterCount < m_firstVisibleCharacter)
  1463. {
  1464. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1465. m_textInfo.characterInfo[m_characterCount].character = (char)0x200B;
  1466. m_characterCount += 1;
  1467. continue;
  1468. }
  1469. // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
  1470. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
  1471. #if TMP_PROFILE_ON
  1472. Profiler.BeginSample("Handle Font Style");
  1473. #endif
  1474. float smallCapsMultiplier = 1.0f;
  1475. if (m_textElementType == TMP_TextElementType.Character)
  1476. {
  1477. if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase)
  1478. {
  1479. // If this character is lowercase, switch to uppercase.
  1480. if (char.IsLower((char)charCode))
  1481. charCode = char.ToUpper((char)charCode);
  1482. }
  1483. else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase)
  1484. {
  1485. // If this character is uppercase, switch to lowercase.
  1486. if (char.IsUpper((char)charCode))
  1487. charCode = char.ToLower((char)charCode);
  1488. }
  1489. else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps)
  1490. {
  1491. if (char.IsLower((char)charCode))
  1492. {
  1493. smallCapsMultiplier = 0.8f;
  1494. charCode = char.ToUpper((char)charCode);
  1495. }
  1496. }
  1497. }
  1498. #if TMP_PROFILE_ON
  1499. Profiler.EndSample();
  1500. #endif
  1501. #endregion
  1502. // Look up Character Data from Dictionary and cache it.
  1503. #region Look up Character Data
  1504. #if TMP_PROFILE_ON
  1505. Profiler.BeginSample("Lookup Character Data");
  1506. #endif
  1507. if (m_textElementType == TMP_TextElementType.Sprite)
  1508. {
  1509. // If a sprite is used as a fallback then get a reference to it and set the color to white.
  1510. m_currentSpriteAsset = m_textInfo.characterInfo[m_characterCount].spriteAsset;
  1511. m_spriteIndex = m_textInfo.characterInfo[m_characterCount].spriteIndex;
  1512. TMP_Sprite sprite = m_currentSpriteAsset.spriteInfoList[m_spriteIndex];
  1513. if (sprite == null) continue;
  1514. // Sprites are assigned in the E000 Private Area + sprite Index
  1515. if (charCode == 60)
  1516. charCode = 57344 + m_spriteIndex;
  1517. else
  1518. m_spriteColor = s_colorWhite;
  1519. // The sprite scale calculations are based on the font asset assigned to the text object.
  1520. float spriteScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale);
  1521. currentElementScale = m_currentFontAsset.fontInfo.Ascender / sprite.height * sprite.scale * spriteScale;
  1522. m_cached_TextElement = sprite;
  1523. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite;
  1524. m_textInfo.characterInfo[m_characterCount].scale = spriteScale;
  1525. m_textInfo.characterInfo[m_characterCount].spriteAsset = m_currentSpriteAsset;
  1526. m_textInfo.characterInfo[m_characterCount].fontAsset = m_currentFontAsset;
  1527. m_textInfo.characterInfo[m_characterCount].materialReferenceIndex = m_currentMaterialIndex;
  1528. m_currentMaterialIndex = prev_MaterialIndex;
  1529. padding = 0;
  1530. }
  1531. else if (m_textElementType == TMP_TextElementType.Character)
  1532. {
  1533. m_cached_TextElement = m_textInfo.characterInfo[m_characterCount].textElement;
  1534. if (m_cached_TextElement == null) continue;
  1535. m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  1536. m_currentMaterial = m_textInfo.characterInfo[m_characterCount].material;
  1537. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  1538. // Re-calculate font scale as the font asset may have changed.
  1539. m_fontScale = m_currentFontSize * smallCapsMultiplier / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale;
  1540. currentElementScale = m_fontScale * m_fontScaleMultiplier * m_cached_TextElement.scale;
  1541. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Character;
  1542. m_textInfo.characterInfo[m_characterCount].scale = currentElementScale;
  1543. padding = m_currentMaterialIndex == 0 ? m_padding : m_subTextObjects[m_currentMaterialIndex].padding;
  1544. }
  1545. #if TMP_PROFILE_ON
  1546. Profiler.EndSample();
  1547. #endif
  1548. #endregion
  1549. // Handle Soft Hyphen
  1550. #region Handle Soft Hyphen
  1551. float old_scale = currentElementScale;
  1552. if (charCode == 0xAD)
  1553. {
  1554. currentElementScale = 0;
  1555. }
  1556. #endregion
  1557. // Store some of the text object's information
  1558. m_textInfo.characterInfo[m_characterCount].character = (char)charCode;
  1559. m_textInfo.characterInfo[m_characterCount].pointSize = m_currentFontSize;
  1560. m_textInfo.characterInfo[m_characterCount].color = m_htmlColor;
  1561. m_textInfo.characterInfo[m_characterCount].underlineColor = m_underlineColor;
  1562. m_textInfo.characterInfo[m_characterCount].strikethroughColor = m_strikethroughColor;
  1563. m_textInfo.characterInfo[m_characterCount].highlightColor = m_highlightColor;
  1564. m_textInfo.characterInfo[m_characterCount].style = m_style;
  1565. m_textInfo.characterInfo[m_characterCount].index = i;
  1566. //m_textInfo.characterInfo[m_characterCount].isIgnoringAlignment = m_isIgnoringAlignment;
  1567. // Handle Kerning if Enabled.
  1568. #region Handle Kerning
  1569. GlyphValueRecord glyphAdjustments = new GlyphValueRecord();
  1570. if (m_enableKerning)
  1571. {
  1572. KerningPair adjustmentPair = null;
  1573. if (m_characterCount < totalCharacterCount - 1)
  1574. {
  1575. uint nextGlyph = m_textInfo.characterInfo[m_characterCount + 1].character;
  1576. KerningPairKey keyValue = new KerningPairKey((uint)charCode, nextGlyph);
  1577. m_currentFontAsset.kerningDictionary.TryGetValue((int)keyValue.key, out adjustmentPair);
  1578. if (adjustmentPair != null)
  1579. glyphAdjustments = adjustmentPair.firstGlyphAdjustments;
  1580. }
  1581. if (m_characterCount >= 1)
  1582. {
  1583. uint previousGlyph = m_textInfo.characterInfo[m_characterCount - 1].character;
  1584. KerningPairKey keyValue = new KerningPairKey(previousGlyph, (uint)charCode);
  1585. m_currentFontAsset.kerningDictionary.TryGetValue((int)keyValue.key, out adjustmentPair);
  1586. if (adjustmentPair != null)
  1587. glyphAdjustments += adjustmentPair.secondGlyphAdjustments;
  1588. }
  1589. }
  1590. #endregion
  1591. // Initial Implementation for RTL support.
  1592. #region Handle Right-to-Left
  1593. if (m_isRightToLeft)
  1594. {
  1595. m_xAdvance -= ((m_cached_TextElement.xAdvance * bold_xAdvance_multiplier + m_characterSpacing + m_wordSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
  1596. if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B)
  1597. m_xAdvance -= m_wordSpacing * currentElementScale;
  1598. }
  1599. #endregion
  1600. // Handle Mono Spacing
  1601. #region Handle Mono Spacing
  1602. float monoAdvance = 0;
  1603. if (m_monoSpacing != 0)
  1604. {
  1605. monoAdvance = (m_monoSpacing / 2 - (m_cached_TextElement.width / 2 + m_cached_TextElement.xOffset) * currentElementScale) * (1 - m_charWidthAdjDelta);
  1606. m_xAdvance += monoAdvance;
  1607. }
  1608. #endregion
  1609. // Set Padding based on selected font style
  1610. #region Handle Style Padding
  1611. if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold)) // Checks for any combination of Bold Style.
  1612. {
  1613. if (m_currentMaterial.HasProperty(ShaderUtilities.ID_GradientScale))
  1614. {
  1615. float gradientScale = m_currentMaterial.GetFloat(ShaderUtilities.ID_GradientScale);
  1616. style_padding = m_currentFontAsset.boldStyle / 4.0f * gradientScale * m_currentMaterial.GetFloat(ShaderUtilities.ID_ScaleRatio_A);
  1617. // Clamp overall padding to Gradient Scale size.
  1618. if (style_padding + padding > gradientScale)
  1619. padding = gradientScale - style_padding;
  1620. }
  1621. else
  1622. style_padding = 0;
  1623. bold_xAdvance_multiplier = 1 + m_currentFontAsset.boldSpacing * 0.01f;
  1624. }
  1625. else
  1626. {
  1627. if (m_currentMaterial.HasProperty(ShaderUtilities.ID_GradientScale))
  1628. {
  1629. float gradientScale = m_currentMaterial.GetFloat(ShaderUtilities.ID_GradientScale);
  1630. style_padding = m_currentFontAsset.normalStyle / 4.0f * gradientScale * m_currentMaterial.GetFloat(ShaderUtilities.ID_ScaleRatio_A);
  1631. // Clamp overall padding to Gradient Scale size.
  1632. if (style_padding + padding > gradientScale)
  1633. padding = gradientScale - style_padding;
  1634. }
  1635. else
  1636. style_padding = 0;
  1637. bold_xAdvance_multiplier = 1.0f;
  1638. }
  1639. #endregion Handle Style Padding
  1640. // Determine the position of the vertices of the Character or Sprite.
  1641. #region Calculate Vertices Position
  1642. #if TMP_PROFILE_ON
  1643. Profiler.BeginSample("Calculate Vertices Position");
  1644. #endif
  1645. float fontBaseLineOffset = m_currentFontAsset.fontInfo.Baseline * m_fontScale * m_fontScaleMultiplier * m_currentFontAsset.fontInfo.Scale;
  1646. Vector3 top_left;
  1647. top_left.x = m_xAdvance + ((m_cached_TextElement.xOffset - padding - style_padding + glyphAdjustments.xPlacement) * currentElementScale * (1 - m_charWidthAdjDelta));
  1648. top_left.y = fontBaseLineOffset + (m_cached_TextElement.yOffset + padding + glyphAdjustments.yPlacement) * currentElementScale - m_lineOffset + m_baselineOffset;
  1649. top_left.z = 0;
  1650. Vector3 bottom_left;
  1651. bottom_left.x = top_left.x;
  1652. bottom_left.y = top_left.y - ((m_cached_TextElement.height + padding * 2) * currentElementScale);
  1653. bottom_left.z = 0;
  1654. Vector3 top_right;
  1655. top_right.x = bottom_left.x + ((m_cached_TextElement.width + padding * 2 + style_padding * 2) * currentElementScale * (1 - m_charWidthAdjDelta));
  1656. top_right.y = top_left.y;
  1657. top_right.z = 0;
  1658. Vector3 bottom_right;
  1659. bottom_right.x = top_right.x;
  1660. bottom_right.y = bottom_left.y;
  1661. bottom_right.z = 0;
  1662. #if TMP_PROFILE_ON
  1663. Profiler.EndSample();
  1664. #endif
  1665. #endregion
  1666. // Check if we need to Shear the rectangles for Italic styles
  1667. #region Handle Italic & Shearing
  1668. if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic))
  1669. {
  1670. // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount.
  1671. float shear_value = m_currentFontAsset.italicStyle * 0.01f;
  1672. Vector3 topShear = new Vector3(shear_value * ((m_cached_TextElement.yOffset + padding + style_padding) * currentElementScale), 0, 0);
  1673. Vector3 bottomShear = new Vector3(shear_value * (((m_cached_TextElement.yOffset - m_cached_TextElement.height - padding - style_padding)) * currentElementScale), 0, 0);
  1674. top_left = top_left + topShear;
  1675. bottom_left = bottom_left + bottomShear;
  1676. top_right = top_right + topShear;
  1677. bottom_right = bottom_right + bottomShear;
  1678. }
  1679. #endregion Handle Italics & Shearing
  1680. // Handle Character Rotation
  1681. #region Handle Character Rotation
  1682. if (m_isFXMatrixSet)
  1683. {
  1684. // Apply scale matrix when simulating Condensed text.
  1685. if (m_FXMatrix.m00 != 1)
  1686. {
  1687. //top_left = m_FXMatrix.MultiplyPoint3x4(top_left);
  1688. //bottom_left = m_FXMatrix.MultiplyPoint3x4(bottom_left);
  1689. //top_right = m_FXMatrix.MultiplyPoint3x4(top_right);
  1690. //bottom_right = m_FXMatrix.MultiplyPoint3x4(bottom_right);
  1691. }
  1692. Vector3 positionOffset = (top_right + bottom_left) / 2;
  1693. top_left = m_FXMatrix.MultiplyPoint3x4(top_left - positionOffset) + positionOffset;
  1694. bottom_left = m_FXMatrix.MultiplyPoint3x4(bottom_left - positionOffset) + positionOffset;
  1695. top_right = m_FXMatrix.MultiplyPoint3x4(top_right - positionOffset) + positionOffset;
  1696. bottom_right = m_FXMatrix.MultiplyPoint3x4(bottom_right - positionOffset) + positionOffset;
  1697. }
  1698. #endregion
  1699. // Store vertex information for the character or sprite.
  1700. m_textInfo.characterInfo[m_characterCount].bottomLeft = bottom_left;
  1701. m_textInfo.characterInfo[m_characterCount].topLeft = top_left;
  1702. m_textInfo.characterInfo[m_characterCount].topRight = top_right;
  1703. m_textInfo.characterInfo[m_characterCount].bottomRight = bottom_right;
  1704. m_textInfo.characterInfo[m_characterCount].origin = m_xAdvance;
  1705. m_textInfo.characterInfo[m_characterCount].baseLine = fontBaseLineOffset - m_lineOffset + m_baselineOffset;
  1706. m_textInfo.characterInfo[m_characterCount].aspectRatio = (top_right.x - bottom_left.x) / (top_left.y - bottom_left.y);
  1707. // Compute and save text element Ascender and maximum line Ascender.
  1708. float elementAscender = m_currentFontAsset.fontInfo.Ascender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale / smallCapsMultiplier : m_textInfo.characterInfo[m_characterCount].scale) + m_baselineOffset;
  1709. m_textInfo.characterInfo[m_characterCount].ascender = elementAscender - m_lineOffset;
  1710. m_maxLineAscender = elementAscender > m_maxLineAscender ? elementAscender : m_maxLineAscender;
  1711. // Compute and save text element Descender and maximum line Descender.
  1712. float elementDescender = m_currentFontAsset.fontInfo.Descender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale / smallCapsMultiplier : m_textInfo.characterInfo[m_characterCount].scale) + m_baselineOffset;
  1713. float elementDescenderII = m_textInfo.characterInfo[m_characterCount].descender = elementDescender - m_lineOffset;
  1714. m_maxLineDescender = elementDescender < m_maxLineDescender ? elementDescender : m_maxLineDescender;
  1715. // Adjust maxLineAscender and maxLineDescender if style is superscript or subscript
  1716. if ((m_style & FontStyles.Subscript) == FontStyles.Subscript || (m_style & FontStyles.Superscript) == FontStyles.Superscript)
  1717. {
  1718. float baseAscender = (elementAscender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize;
  1719. elementAscender = m_maxLineAscender;
  1720. m_maxLineAscender = baseAscender > m_maxLineAscender ? baseAscender : m_maxLineAscender;
  1721. float baseDescender = (elementDescender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize;
  1722. elementDescender = m_maxLineDescender;
  1723. m_maxLineDescender = baseDescender < m_maxLineDescender ? baseDescender : m_maxLineDescender;
  1724. }
  1725. if (m_lineNumber == 0 || m_isNewPage)
  1726. {
  1727. m_maxAscender = m_maxAscender > elementAscender ? m_maxAscender : elementAscender;
  1728. m_maxCapHeight = Mathf.Max(m_maxCapHeight, m_currentFontAsset.fontInfo.CapHeight * currentElementScale / smallCapsMultiplier);
  1729. }
  1730. if (m_lineOffset == 0) pageAscender = pageAscender > elementAscender ? pageAscender : elementAscender;
  1731. // Set Characters to not visible by default.
  1732. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1733. // Setup Mesh for visible text elements. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
  1734. #region Handle Visible Characters
  1735. //#if TMP_PROFILE_ON
  1736. //Profiler.BeginSample("Handle Visible Characters");
  1737. //#endif
  1738. if (charCode == 9 || charCode == 0xA0 || charCode == 0x2007 || (!char.IsWhiteSpace((char)charCode) && charCode != 0x200B) || m_textElementType == TMP_TextElementType.Sprite)
  1739. {
  1740. m_textInfo.characterInfo[m_characterCount].isVisible = true;
  1741. #region Experimental Margin Shaper
  1742. //Vector2 shapedMargins;
  1743. //if (marginShaper)
  1744. //{
  1745. // shapedMargins = m_marginShaper.GetShapedMargins(m_textInfo.characterInfo[m_characterCount].baseLine);
  1746. // if (shapedMargins.x < margins.x)
  1747. // {
  1748. // shapedMargins.x = m_marginLeft;
  1749. // }
  1750. // else
  1751. // {
  1752. // shapedMargins.x += m_marginLeft - margins.x;
  1753. // }
  1754. // if (shapedMargins.y < margins.z)
  1755. // {
  1756. // shapedMargins.y = m_marginRight;
  1757. // }
  1758. // else
  1759. // {
  1760. // shapedMargins.y += m_marginRight - margins.z;
  1761. // }
  1762. //}
  1763. //else
  1764. //{
  1765. // shapedMargins.x = m_marginLeft;
  1766. // shapedMargins.y = m_marginRight;
  1767. //}
  1768. //width = marginWidth + 0.0001f - shapedMargins.x - shapedMargins.y;
  1769. //if (m_width != -1 && m_width < width)
  1770. //{
  1771. // width = m_width;
  1772. //}
  1773. //m_textInfo.lineInfo[m_lineNumber].marginLeft = shapedMargins.x;
  1774. #endregion
  1775. width = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - m_marginLeft - m_marginRight, m_width) : marginWidth + 0.0001f - m_marginLeft - m_marginRight;
  1776. m_textInfo.lineInfo[m_lineNumber].marginLeft = m_marginLeft;
  1777. bool isJustifiedOrFlush = ((_HorizontalAlignmentOptions)m_lineJustification & _HorizontalAlignmentOptions.Flush) == _HorizontalAlignmentOptions.Flush || ((_HorizontalAlignmentOptions)m_lineJustification & _HorizontalAlignmentOptions.Justified) == _HorizontalAlignmentOptions.Justified;
  1778. // Calculate the line breaking width of the text.
  1779. linebreakingWidth = Mathf.Abs(m_xAdvance) + (!m_isRightToLeft ? m_cached_TextElement.xAdvance : 0) * (1 - m_charWidthAdjDelta) * (charCode != 0xAD ? currentElementScale : old_scale);
  1780. // Check if Character exceeds the width of the Text Container
  1781. #region Handle Line Breaking, Text Auto-Sizing and Horizontal Overflow
  1782. if (linebreakingWidth > width * (isJustifiedOrFlush ? 1.05f : 1.0f))
  1783. {
  1784. ellipsisIndex = m_characterCount - 1; // Last safely rendered character
  1785. // Word Wrapping
  1786. #region Handle Word Wrapping
  1787. if (enableWordWrapping && m_characterCount != m_firstCharacterOfLine)
  1788. {
  1789. // Check if word wrapping is still possible
  1790. #region Line Breaking Check
  1791. if (wrappingIndex == m_SavedWordWrapState.previous_WordBreak || isFirstWord)
  1792. {
  1793. // Word wrapping is no longer possible. Shrink size of text if auto-sizing is enabled.
  1794. if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
  1795. {
  1796. // Handle Character Width Adjustments
  1797. #region Character Width Adjustments
  1798. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  1799. {
  1800. loopCountA = 0;
  1801. m_charWidthAdjDelta += 0.01f;
  1802. GenerateTextMesh();
  1803. return;
  1804. }
  1805. #endregion
  1806. // Adjust Point Size
  1807. m_maxFontSize = m_fontSize;
  1808. m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  1809. m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;
  1810. if (loopCountA > 20) return; // Added to debug
  1811. GenerateTextMesh();
  1812. return;
  1813. }
  1814. // Word wrapping is no longer possible, now breaking up individual words.
  1815. if (m_isCharacterWrappingEnabled == false)
  1816. {
  1817. if (ignoreNonBreakingSpace == false)
  1818. ignoreNonBreakingSpace = true;
  1819. else
  1820. m_isCharacterWrappingEnabled = true;
  1821. }
  1822. else
  1823. isLastBreakingChar = true;
  1824. //m_recursiveCount += 1;
  1825. //if (m_recursiveCount > 20)
  1826. //{
  1827. // Debug.Log("Recursive count exceeded!");
  1828. // continue;
  1829. //}
  1830. }
  1831. #endregion
  1832. // Restore to previously stored state of last valid (space character or linefeed)
  1833. i = RestoreWordWrappingState(ref m_SavedWordWrapState);
  1834. wrappingIndex = i; // Used to detect when line length can no longer be reduced.
  1835. // Handling for Soft Hyphen
  1836. if (m_char_buffer[i] == 0xAD) // && !m_isCharacterWrappingEnabled) // && ellipsisIndex != i && !m_isCharacterWrappingEnabled)
  1837. {
  1838. m_isTextTruncated = true;
  1839. m_char_buffer[i] = 0x2D;
  1840. GenerateTextMesh();
  1841. return;
  1842. }
  1843. //Debug.Log("Last Visible Character of line # " + m_lineNumber + " is [" + m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].character + " Character Count: " + m_characterCount + " Last visible: " + m_lastVisibleCharacterOfLine);
  1844. // Check if Line Spacing of previous line needs to be adjusted.
  1845. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET && !m_isNewPage)
  1846. {
  1847. //Debug.Log("(Line Break - Adjusting Line Spacing on line #" + m_lineNumber);
  1848. float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
  1849. AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
  1850. m_lineOffset += offsetDelta;
  1851. m_SavedWordWrapState.lineOffset = m_lineOffset;
  1852. m_SavedWordWrapState.previousLineAscender = m_maxLineAscender;
  1853. // TODO - Add check for character exceeding vertical bounds
  1854. }
  1855. m_isNewPage = false;
  1856. // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
  1857. float lineAscender = m_maxLineAscender - m_lineOffset;
  1858. float lineDescender = m_maxLineDescender - m_lineOffset;
  1859. // Update maxDescender and maxVisibleDescender
  1860. m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
  1861. if (!isMaxVisibleDescenderSet)
  1862. maxVisibleDescender = m_maxDescender;
  1863. if (m_useMaxVisibleDescender && (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines))
  1864. isMaxVisibleDescenderSet = true;
  1865. // Track & Store lineInfo for the new line
  1866. m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
  1867. m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine = m_firstCharacterOfLine > m_firstVisibleCharacterOfLine ? m_firstCharacterOfLine : m_firstVisibleCharacterOfLine;
  1868. m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_lastCharacterOfLine = m_characterCount - 1 > 0 ? m_characterCount - 1 : 0;
  1869. m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine = m_lastVisibleCharacterOfLine < m_firstVisibleCharacterOfLine ? m_firstVisibleCharacterOfLine : m_lastVisibleCharacterOfLine;
  1870. m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;
  1871. m_textInfo.lineInfo[m_lineNumber].visibleCharacterCount = m_lineVisibleCharacterCount;
  1872. m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
  1873. m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
  1874. m_textInfo.lineInfo[m_lineNumber].length = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x;
  1875. m_textInfo.lineInfo[m_lineNumber].width = width;
  1876. //m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
  1877. m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (m_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing;
  1878. m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset;
  1879. m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender;
  1880. m_textInfo.lineInfo[m_lineNumber].descender = lineDescender;
  1881. m_textInfo.lineInfo[m_lineNumber].lineHeight = lineAscender - lineDescender + lineGap * baseScale;
  1882. m_firstCharacterOfLine = m_characterCount; // Store first character of the next line.
  1883. m_lineVisibleCharacterCount = 0;
  1884. // Store the state of the line before starting on the new line.
  1885. SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount - 1);
  1886. m_lineNumber += 1;
  1887. isStartOfNewLine = true;
  1888. isFirstWord = true;
  1889. // Check to make sure Array is large enough to hold a new line.
  1890. if (m_lineNumber >= m_textInfo.lineInfo.Length)
  1891. ResizeLineExtents(m_lineNumber);
  1892. // Apply Line Spacing based on scale of the last character of the line.
  1893. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  1894. {
  1895. float ascender = m_textInfo.characterInfo[m_characterCount].ascender - m_textInfo.characterInfo[m_characterCount].baseLine;
  1896. lineOffsetDelta = 0 - m_maxLineDescender + ascender + (lineGap + m_lineSpacing + m_lineSpacingDelta) * baseScale;
  1897. m_lineOffset += lineOffsetDelta;
  1898. m_startOfLineAscender = ascender;
  1899. }
  1900. else
  1901. m_lineOffset += m_lineHeight + m_lineSpacing * baseScale;
  1902. m_maxLineAscender = k_LargeNegativeFloat;
  1903. m_maxLineDescender = k_LargePositiveFloat;
  1904. m_xAdvance = 0 + tag_Indent;
  1905. continue;
  1906. }
  1907. #endregion End Word Wrapping
  1908. // Text Auto-Sizing (text exceeding Width of container.
  1909. #region Handle Text Auto-Sizing
  1910. if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
  1911. {
  1912. // Handle Character Width Adjustments
  1913. #region Character Width Adjustments
  1914. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  1915. {
  1916. loopCountA = 0;
  1917. m_charWidthAdjDelta += 0.01f;
  1918. GenerateTextMesh();
  1919. return;
  1920. }
  1921. #endregion
  1922. // Adjust Point Size
  1923. m_maxFontSize = m_fontSize;
  1924. m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  1925. m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;
  1926. //m_recursiveCount = 0;
  1927. if (loopCountA > 20) return; // Added to debug
  1928. GenerateTextMesh();
  1929. return;
  1930. }
  1931. #endregion End Text Auto-Sizing
  1932. // Handle Text Overflow
  1933. #region Handle Text Overflow
  1934. switch (m_overflowMode)
  1935. {
  1936. case TextOverflowModes.Overflow:
  1937. if (m_isMaskingEnabled)
  1938. DisableMasking();
  1939. break;
  1940. case TextOverflowModes.Ellipsis:
  1941. if (m_isMaskingEnabled)
  1942. DisableMasking();
  1943. m_isTextTruncated = true;
  1944. if (m_characterCount < 1)
  1945. {
  1946. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1947. //m_visibleCharacterCount = 0;
  1948. break;
  1949. }
  1950. m_char_buffer[i - 1] = 8230;
  1951. m_char_buffer[i] = (char)0;
  1952. if (m_cached_Ellipsis_GlyphInfo != null)
  1953. {
  1954. m_textInfo.characterInfo[ellipsisIndex].character = (char)8230;
  1955. m_textInfo.characterInfo[ellipsisIndex].textElement = m_cached_Ellipsis_GlyphInfo;
  1956. m_textInfo.characterInfo[ellipsisIndex].fontAsset = m_materialReferences[0].fontAsset;
  1957. m_textInfo.characterInfo[ellipsisIndex].material = m_materialReferences[0].material;
  1958. m_textInfo.characterInfo[ellipsisIndex].materialReferenceIndex = 0;
  1959. }
  1960. else
  1961. {
  1962. Debug.LogWarning("Unable to use Ellipsis character since it wasn't found in the current Font Asset [" + m_fontAsset.name + "]. Consider regenerating this font asset to include the Ellipsis character (u+2026).\nNote: Warnings can be disabled in the TMP Settings file.", this);
  1963. }
  1964. m_totalCharacterCount = ellipsisIndex + 1;
  1965. GenerateTextMesh();
  1966. return;
  1967. case TextOverflowModes.Masking:
  1968. if (!m_isMaskingEnabled)
  1969. EnableMasking();
  1970. break;
  1971. case TextOverflowModes.ScrollRect:
  1972. if (!m_isMaskingEnabled)
  1973. EnableMasking();
  1974. break;
  1975. case TextOverflowModes.Truncate:
  1976. if (m_isMaskingEnabled)
  1977. DisableMasking();
  1978. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1979. break;
  1980. case TextOverflowModes.Linked:
  1981. //m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1982. //if (m_linkedTextComponent != null)
  1983. //{
  1984. // m_linkedTextComponent.text = text;
  1985. // m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  1986. // m_linkedTextComponent.ForceMeshUpdate();
  1987. //}
  1988. break;
  1989. }
  1990. #endregion End Text Overflow
  1991. }
  1992. #endregion End Check for Characters Exceeding Width of Text Container
  1993. // Special handling of characters that are not ignored at the end of a line.
  1994. if (charCode == 9 || charCode == 0xA0 || charCode == 0x2007)
  1995. {
  1996. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  1997. m_lastVisibleCharacterOfLine = m_characterCount;
  1998. m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
  1999. m_textInfo.spaceCount += 1;
  2000. if (charCode == 0xA0)
  2001. m_textInfo.lineInfo[m_lineNumber].controlCharacterCount += 1;
  2002. }
  2003. else
  2004. {
  2005. // Determine Vertex Color
  2006. if (m_overrideHtmlColors)
  2007. vertexColor = m_fontColor32;
  2008. else
  2009. vertexColor = m_htmlColor;
  2010. // Store Character & Sprite Vertex Information
  2011. if (m_textElementType == TMP_TextElementType.Character)
  2012. {
  2013. // Save Character Vertex Data
  2014. SaveGlyphVertexInfo(padding, style_padding, vertexColor);
  2015. }
  2016. else if (m_textElementType == TMP_TextElementType.Sprite)
  2017. {
  2018. SaveSpriteVertexInfo(vertexColor);
  2019. }
  2020. }
  2021. // Increase visible count for Characters.
  2022. if (m_textInfo.characterInfo[m_characterCount].isVisible && charCode != 0xAD)
  2023. {
  2024. if (isStartOfNewLine) { isStartOfNewLine = false; m_firstVisibleCharacterOfLine = m_characterCount; }
  2025. m_lineVisibleCharacterCount += 1;
  2026. m_lastVisibleCharacterOfLine = m_characterCount;
  2027. }
  2028. }
  2029. else
  2030. { // This is a Space, Tab, LineFeed or Carriage Return
  2031. // Track # of spaces per line which is used for line justification.
  2032. if ((charCode == 10 || char.IsSeparator((char)charCode)) && charCode != 0xAD && charCode != 0x200B && charCode != 0x2060)
  2033. {
  2034. m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
  2035. m_textInfo.spaceCount += 1;
  2036. }
  2037. }
  2038. //#if TMP_PROFILE_ON
  2039. //Profiler.EndSample();
  2040. //#endif
  2041. #endregion Handle Visible Characters
  2042. // Check if Line Spacing of previous line needs to be adjusted.
  2043. #region Adjust Line Spacing
  2044. #if TMP_PROFILE_ON
  2045. Profiler.BeginSample("Adjust Line Spacing");
  2046. #endif
  2047. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET && !m_isNewPage)
  2048. {
  2049. //Debug.Log("Inline - Adjusting Line Spacing on line #" + m_lineNumber);
  2050. //float gap = 0; // Compute gap.
  2051. float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
  2052. AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
  2053. elementDescenderII -= offsetDelta;
  2054. m_lineOffset += offsetDelta;
  2055. m_startOfLineAscender += offsetDelta;
  2056. m_SavedWordWrapState.lineOffset = m_lineOffset;
  2057. m_SavedWordWrapState.previousLineAscender = m_startOfLineAscender;
  2058. }
  2059. #if TMP_PROFILE_ON
  2060. Profiler.EndSample();
  2061. #endif
  2062. #endregion
  2063. // Store Rectangle positions for each Character.
  2064. #region Store Character Data
  2065. m_textInfo.characterInfo[m_characterCount].lineNumber = m_lineNumber;
  2066. m_textInfo.characterInfo[m_characterCount].pageNumber = m_pageNumber;
  2067. if (charCode != 10 && charCode != 13 && charCode != 8230 || m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
  2068. m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
  2069. #endregion Store Character Data
  2070. // Check if text Exceeds the vertical bounds of the margin area.
  2071. #region Check Vertical Bounds & Auto-Sizing
  2072. #if TMP_PROFILE_ON
  2073. Profiler.BeginSample("Check Vertical Bounds");
  2074. #endif
  2075. if (m_maxAscender - elementDescenderII > marginHeight + 0.0001f)
  2076. {
  2077. // Handle Line spacing adjustments
  2078. #region Line Spacing Adjustments
  2079. if (m_enableAutoSizing && m_lineSpacingDelta > m_lineSpacingMax && m_lineNumber > 0)
  2080. {
  2081. loopCountA = 0;
  2082. m_lineSpacingDelta -= 1;
  2083. GenerateTextMesh();
  2084. return;
  2085. }
  2086. #endregion
  2087. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  2088. #region Text Auto-Sizing (Text greater than vertical bounds)
  2089. if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
  2090. {
  2091. m_maxFontSize = m_fontSize;
  2092. m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  2093. m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;
  2094. //m_recursiveCount = 0;
  2095. if (loopCountA > 20) return; // Added to debug
  2096. GenerateTextMesh();
  2097. return;
  2098. }
  2099. #endregion Text Auto-Sizing
  2100. // Set isTextOverflowing and firstOverflowCharacterIndex
  2101. if (m_firstOverflowCharacterIndex == -1)
  2102. m_firstOverflowCharacterIndex = m_characterCount;
  2103. // Handle Text Overflow
  2104. #region Text Overflow
  2105. switch (m_overflowMode)
  2106. {
  2107. case TextOverflowModes.Overflow:
  2108. if (m_isMaskingEnabled)
  2109. DisableMasking();
  2110. break;
  2111. case TextOverflowModes.Ellipsis:
  2112. if (m_isMaskingEnabled)
  2113. DisableMasking();
  2114. if (m_lineNumber > 0)
  2115. {
  2116. m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index] = 8230;
  2117. m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
  2118. if (m_cached_Ellipsis_GlyphInfo != null)
  2119. {
  2120. m_textInfo.characterInfo[ellipsisIndex].character = (char)8230;
  2121. m_textInfo.characterInfo[ellipsisIndex].textElement = m_cached_Ellipsis_GlyphInfo;
  2122. m_textInfo.characterInfo[ellipsisIndex].fontAsset = m_materialReferences[0].fontAsset;
  2123. m_textInfo.characterInfo[ellipsisIndex].material = m_materialReferences[0].material;
  2124. m_textInfo.characterInfo[ellipsisIndex].materialReferenceIndex = 0;
  2125. }
  2126. else
  2127. {
  2128. Debug.LogWarning("Unable to use Ellipsis character since it wasn't found in the current Font Asset [" + m_fontAsset.name + "]. Consider regenerating this font asset to include the Ellipsis character (u+2026).\nNote: Warnings can be disabled in the TMP Settings file.", this);
  2129. }
  2130. m_totalCharacterCount = ellipsisIndex + 1;
  2131. GenerateTextMesh();
  2132. m_isTextTruncated = true;
  2133. return;
  2134. }
  2135. else
  2136. {
  2137. ClearMesh();
  2138. return;
  2139. }
  2140. case TextOverflowModes.Masking:
  2141. if (!m_isMaskingEnabled)
  2142. EnableMasking();
  2143. break;
  2144. case TextOverflowModes.ScrollRect:
  2145. if (!m_isMaskingEnabled)
  2146. EnableMasking();
  2147. break;
  2148. case TextOverflowModes.Truncate:
  2149. if (m_isMaskingEnabled)
  2150. DisableMasking();
  2151. // TODO : Optimize
  2152. if (m_lineNumber > 0)
  2153. {
  2154. m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
  2155. m_totalCharacterCount = ellipsisIndex + 1;
  2156. GenerateTextMesh();
  2157. m_isTextTruncated = true;
  2158. return;
  2159. }
  2160. else
  2161. {
  2162. ClearMesh();
  2163. return;
  2164. }
  2165. case TextOverflowModes.Page:
  2166. if (m_isMaskingEnabled)
  2167. DisableMasking();
  2168. // Ignore Page Break, Linefeed or carriage return
  2169. if (charCode == 13 || charCode == 10)
  2170. break;
  2171. // Return if the first character doesn't fit.
  2172. if (i == 0)
  2173. {
  2174. ClearMesh();
  2175. return;
  2176. }
  2177. else if (previousPageOverflowChar == i)
  2178. {
  2179. m_char_buffer[i] = 0;
  2180. m_isTextTruncated = true;
  2181. }
  2182. previousPageOverflowChar = i;
  2183. // Go back to previous line and re-layout
  2184. i = RestoreWordWrappingState(ref m_SavedLineState);
  2185. m_isNewPage = true;
  2186. m_xAdvance = 0 + tag_Indent;
  2187. m_lineOffset = 0;
  2188. m_maxAscender = 0;
  2189. pageAscender = 0;
  2190. m_lineNumber += 1;
  2191. m_pageNumber += 1;
  2192. continue;
  2193. case TextOverflowModes.Linked:
  2194. if (m_linkedTextComponent != null)
  2195. {
  2196. m_linkedTextComponent.text = text;
  2197. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  2198. m_linkedTextComponent.ForceMeshUpdate();
  2199. }
  2200. // Truncate remaining text
  2201. if (m_lineNumber > 0)
  2202. {
  2203. m_char_buffer[i] = (char)0;
  2204. m_totalCharacterCount = m_characterCount;
  2205. // TODO : Optimize as we should be able to end the layout phase here without having to do another pass.
  2206. GenerateTextMesh();
  2207. m_isTextTruncated = true;
  2208. return;
  2209. }
  2210. else
  2211. {
  2212. ClearMesh();
  2213. return;
  2214. }
  2215. }
  2216. #endregion End Text Overflow
  2217. }
  2218. #if TMP_PROFILE_ON
  2219. Profiler.EndSample();
  2220. #endif
  2221. #endregion Check Vertical Bounds
  2222. // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
  2223. #region XAdvance, Tabulation & Stops
  2224. if (charCode == 9)
  2225. {
  2226. float tabSize = m_currentFontAsset.fontInfo.TabWidth * currentElementScale;
  2227. float tabs = Mathf.Ceil(m_xAdvance / tabSize) * tabSize;
  2228. m_xAdvance = tabs > m_xAdvance ? tabs : m_xAdvance + tabSize;
  2229. }
  2230. else if (m_monoSpacing != 0)
  2231. {
  2232. m_xAdvance += (m_monoSpacing - monoAdvance + ((m_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta);
  2233. if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B)
  2234. m_xAdvance += m_wordSpacing * currentElementScale;
  2235. }
  2236. else if (!m_isRightToLeft)
  2237. {
  2238. float scaleFXMultiplier = 1;
  2239. if (m_isFXMatrixSet) scaleFXMultiplier = m_FXMatrix.m00;
  2240. m_xAdvance += ((m_cached_TextElement.xAdvance * scaleFXMultiplier * bold_xAdvance_multiplier + m_characterSpacing + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
  2241. if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B)
  2242. m_xAdvance += m_wordSpacing * currentElementScale;
  2243. }
  2244. else
  2245. {
  2246. m_xAdvance -= glyphAdjustments.xAdvance * currentElementScale;
  2247. }
  2248. // Store xAdvance information
  2249. m_textInfo.characterInfo[m_characterCount].xAdvance = m_xAdvance;
  2250. #endregion Tabulation & Stops
  2251. // Handle Carriage Return
  2252. #region Carriage Return
  2253. if (charCode == 13)
  2254. {
  2255. m_xAdvance = 0 + tag_Indent;
  2256. }
  2257. #endregion Carriage Return
  2258. // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
  2259. #region Check for Line Feed and Last Character
  2260. #if TMP_PROFILE_ON
  2261. Profiler.BeginSample("Process Linefeed");
  2262. #endif
  2263. if (charCode == 10 || m_characterCount == totalCharacterCount - 1)
  2264. {
  2265. // Check if Line Spacing of previous line needs to be adjusted.
  2266. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET && !m_isNewPage)
  2267. {
  2268. //Debug.Log("Line Feed - Adjusting Line Spacing on line #" + m_lineNumber);
  2269. float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
  2270. AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
  2271. elementDescenderII -= offsetDelta;
  2272. m_lineOffset += offsetDelta;
  2273. }
  2274. m_isNewPage = false;
  2275. // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
  2276. float lineAscender = m_maxLineAscender - m_lineOffset;
  2277. float lineDescender = m_maxLineDescender - m_lineOffset;
  2278. // Update maxDescender and maxVisibleDescender
  2279. m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
  2280. if (!isMaxVisibleDescenderSet)
  2281. maxVisibleDescender = m_maxDescender;
  2282. if (m_useMaxVisibleDescender && (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines))
  2283. isMaxVisibleDescenderSet = true;
  2284. // Save Line Information
  2285. m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
  2286. m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine = m_firstCharacterOfLine > m_firstVisibleCharacterOfLine ? m_firstCharacterOfLine : m_firstVisibleCharacterOfLine;
  2287. m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_lastCharacterOfLine = m_characterCount;
  2288. m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine = m_lastVisibleCharacterOfLine < m_firstVisibleCharacterOfLine ? m_firstVisibleCharacterOfLine : m_lastVisibleCharacterOfLine;
  2289. m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;
  2290. m_textInfo.lineInfo[m_lineNumber].visibleCharacterCount = m_lineVisibleCharacterCount;
  2291. m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
  2292. m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
  2293. m_textInfo.lineInfo[m_lineNumber].length = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - (padding * currentElementScale);
  2294. m_textInfo.lineInfo[m_lineNumber].width = width;
  2295. if (m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
  2296. m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
  2297. if (m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].isVisible)
  2298. m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (m_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing;
  2299. else
  2300. m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastCharacterOfLine].xAdvance - (m_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing;
  2301. m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset;
  2302. m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender;
  2303. m_textInfo.lineInfo[m_lineNumber].descender = lineDescender;
  2304. m_textInfo.lineInfo[m_lineNumber].lineHeight = lineAscender - lineDescender + lineGap * baseScale;
  2305. m_firstCharacterOfLine = m_characterCount + 1;
  2306. m_lineVisibleCharacterCount = 0;
  2307. // Add new line if not last line or character.
  2308. if (charCode == 10)
  2309. {
  2310. // Store the state of the line before starting on the new line.
  2311. SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount);
  2312. // Store the state of the last Character before the new line.
  2313. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2314. m_lineNumber += 1;
  2315. isStartOfNewLine = true;
  2316. ignoreNonBreakingSpace = false;
  2317. isFirstWord = true;
  2318. // Check to make sure Array is large enough to hold a new line.
  2319. if (m_lineNumber >= m_textInfo.lineInfo.Length)
  2320. ResizeLineExtents(m_lineNumber);
  2321. // Apply Line Spacing
  2322. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  2323. {
  2324. lineOffsetDelta = 0 - m_maxLineDescender + elementAscender + (lineGap + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * baseScale;
  2325. m_lineOffset += lineOffsetDelta;
  2326. }
  2327. else
  2328. m_lineOffset += m_lineHeight + (m_lineSpacing + m_paragraphSpacing) * baseScale;
  2329. m_maxLineAscender = k_LargeNegativeFloat;
  2330. m_maxLineDescender = k_LargePositiveFloat;
  2331. m_startOfLineAscender = elementAscender;
  2332. m_xAdvance = 0 + tag_LineIndent + tag_Indent;
  2333. ellipsisIndex = m_characterCount - 1;
  2334. m_characterCount += 1;
  2335. continue;
  2336. }
  2337. }
  2338. #if TMP_PROFILE_ON
  2339. Profiler.EndSample();
  2340. #endif
  2341. #endregion Check for Linefeed or Last Character
  2342. // Store Rectangle positions for each Character.
  2343. #region Save CharacterInfo for the current character.
  2344. #if TMP_PROFILE_ON
  2345. Profiler.BeginSample("Save CharacterInfo & Extents");
  2346. #endif
  2347. // Determine the bounds of the Mesh.
  2348. if (m_textInfo.characterInfo[m_characterCount].isVisible)
  2349. {
  2350. m_meshExtents.min.x = Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x);
  2351. m_meshExtents.min.y = Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y);
  2352. m_meshExtents.max.x = Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x);
  2353. m_meshExtents.max.y = Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topRight.y);
  2354. //m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y));
  2355. //m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topRight.y));
  2356. }
  2357. // Save pageInfo Data
  2358. if (m_overflowMode == TextOverflowModes.Page && charCode != 13 && charCode != 10) // && m_pageNumber < 16)
  2359. {
  2360. // Check if we need to increase allocations for the pageInfo array.
  2361. if (m_pageNumber + 1 > m_textInfo.pageInfo.Length)
  2362. TMP_TextInfo.Resize(ref m_textInfo.pageInfo, m_pageNumber + 1, true);
  2363. m_textInfo.pageInfo[m_pageNumber].ascender = pageAscender;
  2364. m_textInfo.pageInfo[m_pageNumber].descender = elementDescender < m_textInfo.pageInfo[m_pageNumber].descender ? elementDescender : m_textInfo.pageInfo[m_pageNumber].descender;
  2365. if (m_pageNumber == 0 && m_characterCount == 0)
  2366. m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
  2367. else if (m_characterCount > 0 && m_pageNumber != m_textInfo.characterInfo[m_characterCount - 1].pageNumber)
  2368. {
  2369. m_textInfo.pageInfo[m_pageNumber - 1].lastCharacterIndex = m_characterCount - 1;
  2370. m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
  2371. }
  2372. else if (m_characterCount == totalCharacterCount - 1)
  2373. m_textInfo.pageInfo[m_pageNumber].lastCharacterIndex = m_characterCount;
  2374. }
  2375. #if TMP_PROFILE_ON
  2376. Profiler.EndSample();
  2377. #endif
  2378. #endregion Saving CharacterInfo
  2379. // Save State of Mesh Creation for handling of Word Wrapping
  2380. #region Save Word Wrapping State
  2381. #if TMP_PROFILE_ON
  2382. Profiler.BeginSample("Save Word Wrapping State");
  2383. #endif
  2384. if (m_enableWordWrapping || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis)
  2385. {
  2386. if ((char.IsWhiteSpace((char)charCode) || charCode == 0x200B || charCode == 0x2D || charCode == 0xAD) && (!m_isNonBreakingSpace || ignoreNonBreakingSpace) && charCode != 0xA0 && charCode != 0x2007 && charCode != 0x2011 && charCode != 0x202F && charCode != 0x2060)
  2387. {
  2388. // We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored
  2389. // for Word Wrapping.
  2390. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2391. m_isCharacterWrappingEnabled = false;
  2392. isFirstWord = false;
  2393. }
  2394. // Handling for East Asian languages
  2395. else if (( charCode > 0x1100 && charCode < 0x11ff || /* Hangul Jamo */
  2396. charCode > 0x2E80 && charCode < 0x9FFF || /* CJK */
  2397. charCode > 0xA960 && charCode < 0xA97F || /* Hangul Jame Extended-A */
  2398. charCode > 0xAC00 && charCode < 0xD7FF || /* Hangul Syllables */
  2399. charCode > 0xF900 && charCode < 0xFAFF || /* CJK Compatibility Ideographs */
  2400. charCode > 0xFE30 && charCode < 0xFE4F || /* CJK Compatibility Forms */
  2401. charCode > 0xFF00 && charCode < 0xFFEF) /* CJK Halfwidth */
  2402. && !m_isNonBreakingSpace)
  2403. {
  2404. if (isFirstWord || isLastBreakingChar || TMP_Settings.linebreakingRules.leadingCharacters.ContainsKey(charCode) == false &&
  2405. (m_characterCount < totalCharacterCount - 1 &&
  2406. TMP_Settings.linebreakingRules.followingCharacters.ContainsKey(m_textInfo.characterInfo[m_characterCount + 1].character) == false))
  2407. {
  2408. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2409. m_isCharacterWrappingEnabled = false;
  2410. isFirstWord = false;
  2411. }
  2412. }
  2413. else if ((isFirstWord || m_isCharacterWrappingEnabled == true || isLastBreakingChar))
  2414. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  2415. }
  2416. #if TMP_PROFILE_ON
  2417. Profiler.EndSample();
  2418. #endif
  2419. #endregion Save Word Wrapping State
  2420. m_characterCount += 1;
  2421. }
  2422. // Check Auto Sizing and increase font size to fill text container.
  2423. #region Check Auto-Sizing (Upper Font Size Bounds)
  2424. fontSizeDelta = m_maxFontSize - m_minFontSize;
  2425. if (!m_isCharacterWrappingEnabled && m_enableAutoSizing && fontSizeDelta > 0.051f && m_fontSize < m_fontSizeMax)
  2426. {
  2427. m_minFontSize = m_fontSize;
  2428. m_fontSize += Mathf.Max((m_maxFontSize - m_fontSize) / 2, 0.05f);
  2429. m_fontSize = (int)(Mathf.Min(m_fontSize, m_fontSizeMax) * 20 + 0.5f) / 20f;
  2430. //Debug.Log(m_fontSize);
  2431. if (loopCountA > 20) return; // Added to debug
  2432. GenerateTextMesh();
  2433. return;
  2434. }
  2435. #endregion End Auto-sizing Check
  2436. m_isCharacterWrappingEnabled = false;
  2437. #if TMP_PROFILE_PHASES_ON
  2438. Profiler.EndSample();
  2439. #endif
  2440. //Debug.Log("Iteration Count: " + loopCountA + ". Final Point Size: " + m_fontSize); // + " B: " + loopCountB + " C: " + loopCountC + " D: " + loopCountD);
  2441. // *** PHASE II of Text Generation ***
  2442. #if TMP_PROFILE_PHASES_ON
  2443. Profiler.BeginSample("TMP Generate Text - Phase II");
  2444. #endif
  2445. // If there are no visible characters... no need to continue
  2446. if (m_characterCount == 0) // && m_visibleSpriteCount == 0)
  2447. {
  2448. ClearMesh();
  2449. // Event indicating the text has been regenerated.
  2450. TMPro_EventManager.ON_TEXT_CHANGED(this);
  2451. return;
  2452. }
  2453. // *** PHASE II of Text Generation ***
  2454. int last_vert_index = m_materialReferences[0].referenceCount * 4;
  2455. // Partial clear of the vertices array to mark unused vertices as degenerate.
  2456. m_textInfo.meshInfo[0].Clear(false);
  2457. // Handle Text Alignment
  2458. #region Text Vertical Alignment
  2459. #if TMP_PROFILE_ON
  2460. Profiler.BeginSample("Vertical Text Alignment");
  2461. #endif
  2462. Vector3 anchorOffset = Vector3.zero;
  2463. Vector3[] corners = m_RectTransformCorners; // GetTextContainerLocalCorners();
  2464. switch (m_textAlignment)
  2465. {
  2466. // Top Vertically
  2467. case TextAlignmentOptions.Top:
  2468. case TextAlignmentOptions.TopLeft:
  2469. case TextAlignmentOptions.TopRight:
  2470. case TextAlignmentOptions.TopJustified:
  2471. case TextAlignmentOptions.TopFlush:
  2472. case TextAlignmentOptions.TopGeoAligned:
  2473. if (m_overflowMode != TextOverflowModes.Page)
  2474. anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_maxAscender - margins.y, 0);
  2475. else
  2476. anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].ascender - margins.y, 0);
  2477. break;
  2478. // Middle Vertically
  2479. case TextAlignmentOptions.Left:
  2480. case TextAlignmentOptions.Right:
  2481. case TextAlignmentOptions.Center:
  2482. case TextAlignmentOptions.Justified:
  2483. case TextAlignmentOptions.Flush:
  2484. case TextAlignmentOptions.CenterGeoAligned:
  2485. if (m_overflowMode != TextOverflowModes.Page)
  2486. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxAscender + margins.y + maxVisibleDescender - margins.w) / 2, 0);
  2487. else
  2488. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_textInfo.pageInfo[pageToDisplay].ascender + margins.y + m_textInfo.pageInfo[pageToDisplay].descender - margins.w) / 2, 0);
  2489. break;
  2490. // Bottom Vertically
  2491. case TextAlignmentOptions.Bottom:
  2492. case TextAlignmentOptions.BottomLeft:
  2493. case TextAlignmentOptions.BottomRight:
  2494. case TextAlignmentOptions.BottomJustified:
  2495. case TextAlignmentOptions.BottomFlush:
  2496. case TextAlignmentOptions.BottomGeoAligned:
  2497. if (m_overflowMode != TextOverflowModes.Page)
  2498. anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - maxVisibleDescender + margins.w, 0);
  2499. else
  2500. anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].descender + margins.w, 0);
  2501. break;
  2502. // Baseline Vertically
  2503. case TextAlignmentOptions.Baseline:
  2504. case TextAlignmentOptions.BaselineLeft:
  2505. case TextAlignmentOptions.BaselineRight:
  2506. case TextAlignmentOptions.BaselineJustified:
  2507. case TextAlignmentOptions.BaselineFlush:
  2508. case TextAlignmentOptions.BaselineGeoAligned:
  2509. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0, 0);
  2510. break;
  2511. // Midline Vertically
  2512. case TextAlignmentOptions.MidlineLeft:
  2513. case TextAlignmentOptions.Midline:
  2514. case TextAlignmentOptions.MidlineRight:
  2515. case TextAlignmentOptions.MidlineJustified:
  2516. case TextAlignmentOptions.MidlineFlush:
  2517. case TextAlignmentOptions.MidlineGeoAligned:
  2518. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_meshExtents.max.y + margins.y + m_meshExtents.min.y - margins.w) / 2, 0);
  2519. break;
  2520. // Capline Vertically
  2521. case TextAlignmentOptions.CaplineLeft:
  2522. case TextAlignmentOptions.Capline:
  2523. case TextAlignmentOptions.CaplineRight:
  2524. case TextAlignmentOptions.CaplineJustified:
  2525. case TextAlignmentOptions.CaplineFlush:
  2526. case TextAlignmentOptions.CaplineGeoAligned:
  2527. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxCapHeight - margins.y - margins.w) / 2, 0);
  2528. break;
  2529. }
  2530. #if TMP_PROFILE_ON
  2531. Profiler.EndSample();
  2532. #endif
  2533. #endregion
  2534. // Initialization for Second Pass
  2535. Vector3 justificationOffset = Vector3.zero;
  2536. Vector3 offset = Vector3.zero;
  2537. int vert_index_X4 = 0;
  2538. int sprite_index_X4 = 0;
  2539. int wordCount = 0;
  2540. int lineCount = 0;
  2541. int lastLine = 0;
  2542. bool isFirstSeperator = false;
  2543. bool isStartOfWord = false;
  2544. int wordFirstChar = 0;
  2545. int wordLastChar = 0;
  2546. // Second Pass : Line Justification, UV Mapping, Character & Line Visibility & more.
  2547. #region Handle Line Justification & UV Mapping & Character Visibility & More
  2548. // Variables used to handle Canvas Render Modes and SDF Scaling
  2549. bool isCameraAssigned = m_canvas.worldCamera == null ? false : true;
  2550. float lossyScale = m_previousLossyScaleY = this.transform.lossyScale.y;
  2551. RenderMode canvasRenderMode = m_canvas.renderMode;
  2552. float canvasScaleFactor = m_canvas.scaleFactor;
  2553. Color32 underlineColor = Color.white;
  2554. Color32 strikethroughColor = Color.white;
  2555. Color32 highlightColor = new Color32(255, 255, 0, 64);
  2556. float xScale = 0;
  2557. float underlineStartScale = 0;
  2558. float underlineEndScale = 0;
  2559. float underlineMaxScale = 0;
  2560. float underlineBaseLine = k_LargePositiveFloat;
  2561. int lastPage = 0;
  2562. float strikethroughPointSize = 0;
  2563. float strikethroughScale = 0;
  2564. float strikethroughBaseline = 0;
  2565. TMP_CharacterInfo[] characterInfos = m_textInfo.characterInfo;
  2566. #region Handle Line Justification & UV Mapping & Character Visibility & More
  2567. for (int i = 0; i < m_characterCount; i++)
  2568. {
  2569. TMP_FontAsset currentFontAsset = characterInfos[i].fontAsset;
  2570. char currentCharacter = characterInfos[i].character;
  2571. int currentLine = characterInfos[i].lineNumber;
  2572. TMP_LineInfo lineInfo = m_textInfo.lineInfo[currentLine];
  2573. lineCount = currentLine + 1;
  2574. TextAlignmentOptions lineAlignment = lineInfo.alignment;
  2575. // Process Line Justification
  2576. #region Handle Line Justification
  2577. #if TMP_PROFILE_ON
  2578. Profiler.BeginSample("Horizontal Text Alignment");
  2579. #endif
  2580. //if (!characterInfos[i].isIgnoringAlignment)
  2581. //{
  2582. switch (lineAlignment)
  2583. {
  2584. case TextAlignmentOptions.TopLeft:
  2585. case TextAlignmentOptions.Left:
  2586. case TextAlignmentOptions.BottomLeft:
  2587. case TextAlignmentOptions.BaselineLeft:
  2588. case TextAlignmentOptions.MidlineLeft:
  2589. case TextAlignmentOptions.CaplineLeft:
  2590. if (!m_isRightToLeft)
  2591. justificationOffset = new Vector3(0 + lineInfo.marginLeft, 0, 0);
  2592. else
  2593. justificationOffset = new Vector3(0 - lineInfo.maxAdvance, 0, 0);
  2594. break;
  2595. case TextAlignmentOptions.Top:
  2596. case TextAlignmentOptions.Center:
  2597. case TextAlignmentOptions.Bottom:
  2598. case TextAlignmentOptions.Baseline:
  2599. case TextAlignmentOptions.Midline:
  2600. case TextAlignmentOptions.Capline:
  2601. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - lineInfo.maxAdvance / 2, 0, 0);
  2602. break;
  2603. case TextAlignmentOptions.TopGeoAligned:
  2604. case TextAlignmentOptions.CenterGeoAligned:
  2605. case TextAlignmentOptions.BottomGeoAligned:
  2606. case TextAlignmentOptions.BaselineGeoAligned:
  2607. case TextAlignmentOptions.MidlineGeoAligned:
  2608. case TextAlignmentOptions.CaplineGeoAligned:
  2609. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - (lineInfo.lineExtents.min.x + lineInfo.lineExtents.max.x) / 2, 0, 0);
  2610. break;
  2611. case TextAlignmentOptions.TopRight:
  2612. case TextAlignmentOptions.Right:
  2613. case TextAlignmentOptions.BottomRight:
  2614. case TextAlignmentOptions.BaselineRight:
  2615. case TextAlignmentOptions.MidlineRight:
  2616. case TextAlignmentOptions.CaplineRight:
  2617. if (!m_isRightToLeft)
  2618. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width - lineInfo.maxAdvance, 0, 0);
  2619. else
  2620. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0);
  2621. break;
  2622. case TextAlignmentOptions.TopJustified:
  2623. case TextAlignmentOptions.Justified:
  2624. case TextAlignmentOptions.BottomJustified:
  2625. case TextAlignmentOptions.BaselineJustified:
  2626. case TextAlignmentOptions.MidlineJustified:
  2627. case TextAlignmentOptions.CaplineJustified:
  2628. case TextAlignmentOptions.TopFlush:
  2629. case TextAlignmentOptions.Flush:
  2630. case TextAlignmentOptions.BottomFlush:
  2631. case TextAlignmentOptions.BaselineFlush:
  2632. case TextAlignmentOptions.MidlineFlush:
  2633. case TextAlignmentOptions.CaplineFlush:
  2634. // Skip Zero Width Characters
  2635. if (currentCharacter == 0xAD || currentCharacter == 0x200B || currentCharacter == 0x2060) break;
  2636. char lastCharOfCurrentLine = characterInfos[lineInfo.lastCharacterIndex].character;
  2637. bool isFlush = ((_HorizontalAlignmentOptions)lineAlignment & _HorizontalAlignmentOptions.Flush) == _HorizontalAlignmentOptions.Flush;
  2638. // In Justified mode, all lines are justified except the last one.
  2639. // In Flush mode, all lines are justified.
  2640. if (char.IsControl(lastCharOfCurrentLine) == false && currentLine < m_lineNumber || isFlush || lineInfo.maxAdvance > lineInfo.width)
  2641. {
  2642. // First character of each line.
  2643. if (currentLine != lastLine || i == 0 || i == m_firstVisibleCharacter)
  2644. {
  2645. if (!m_isRightToLeft)
  2646. justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0);
  2647. else
  2648. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0);
  2649. if (char.IsSeparator(currentCharacter))
  2650. isFirstSeperator = true;
  2651. else
  2652. isFirstSeperator = false;
  2653. }
  2654. else
  2655. {
  2656. float gap = !m_isRightToLeft ? lineInfo.width - lineInfo.maxAdvance : lineInfo.width + lineInfo.maxAdvance;
  2657. int visibleCount = lineInfo.visibleCharacterCount - 1 + lineInfo.controlCharacterCount;
  2658. // Get the number of spaces for each line ignoring the last character if it is not visible (ie. a space or linefeed).
  2659. int spaces = (characterInfos[lineInfo.lastCharacterIndex].isVisible ? lineInfo.spaceCount : lineInfo.spaceCount - 1) - lineInfo.controlCharacterCount;
  2660. if (isFirstSeperator) { spaces -= 1; visibleCount += 1; }
  2661. float ratio = spaces > 0 ? m_wordWrappingRatios : 1;
  2662. if (spaces < 1) spaces = 1;
  2663. if (currentCharacter != 0xA0 && (currentCharacter == 9 || char.IsSeparator((char)currentCharacter)))
  2664. {
  2665. if (!m_isRightToLeft)
  2666. justificationOffset += new Vector3(gap * (1 - ratio) / spaces, 0, 0);
  2667. else
  2668. justificationOffset -= new Vector3(gap * (1 - ratio) / spaces, 0, 0);
  2669. }
  2670. else
  2671. {
  2672. if (!m_isRightToLeft)
  2673. justificationOffset += new Vector3(gap * ratio / visibleCount, 0, 0);
  2674. else
  2675. justificationOffset -= new Vector3(gap * ratio / visibleCount, 0, 0);
  2676. }
  2677. }
  2678. }
  2679. else
  2680. {
  2681. if (!m_isRightToLeft)
  2682. justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0); // Keep last line left justified.
  2683. else
  2684. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0); // Keep last line right justified.
  2685. }
  2686. //Debug.Log("Char [" + (char)charCode + "] Code:" + charCode + " Line # " + currentLine + " Offset:" + justificationOffset + " # Spaces:" + lineInfo.spaceCount + " # Characters:" + lineInfo.characterCount);
  2687. break;
  2688. }
  2689. //}
  2690. #if TMP_PROFILE_ON
  2691. Profiler.EndSample();
  2692. #endif
  2693. #endregion End Text Justification
  2694. offset = anchorOffset + justificationOffset;
  2695. // Handle UV2 mapping options and packing of scale information into UV2.
  2696. #region Handling of UV2 mapping & Scale packing
  2697. bool isCharacterVisible = characterInfos[i].isVisible;
  2698. if (isCharacterVisible)
  2699. {
  2700. TMP_TextElementType elementType = characterInfos[i].elementType;
  2701. switch (elementType)
  2702. {
  2703. // CHARACTERS
  2704. case TMP_TextElementType.Character:
  2705. Extents lineExtents = lineInfo.lineExtents;
  2706. float uvOffset = (m_uvLineOffset * currentLine) % 1; // + m_uvOffset.x;
  2707. // Setup UV2 based on Character Mapping Options Selected
  2708. #region Handle UV Mapping Options
  2709. #if TMP_PROFILE_ON
  2710. Profiler.BeginSample("UV MAPPING");
  2711. #endif
  2712. switch (m_horizontalMapping)
  2713. {
  2714. case TextureMappingOptions.Character:
  2715. characterInfos[i].vertex_BL.uv2.x = 0; //+ m_uvOffset.x;
  2716. characterInfos[i].vertex_TL.uv2.x = 0; //+ m_uvOffset.x;
  2717. characterInfos[i].vertex_TR.uv2.x = 1; //+ m_uvOffset.x;
  2718. characterInfos[i].vertex_BR.uv2.x = 1; //+ m_uvOffset.x;
  2719. break;
  2720. case TextureMappingOptions.Line:
  2721. if (m_textAlignment != TextAlignmentOptions.Justified)
  2722. {
  2723. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2724. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2725. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2726. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  2727. break;
  2728. }
  2729. else // Special Case if Justified is used in Line Mode.
  2730. {
  2731. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2732. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2733. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2734. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2735. break;
  2736. }
  2737. case TextureMappingOptions.Paragraph:
  2738. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2739. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2740. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2741. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  2742. break;
  2743. case TextureMappingOptions.MatchAspect:
  2744. switch (m_verticalMapping)
  2745. {
  2746. case TextureMappingOptions.Character:
  2747. characterInfos[i].vertex_BL.uv2.y = 0; // + m_uvOffset.y;
  2748. characterInfos[i].vertex_TL.uv2.y = 1; // + m_uvOffset.y;
  2749. characterInfos[i].vertex_TR.uv2.y = 0; // + m_uvOffset.y;
  2750. characterInfos[i].vertex_BR.uv2.y = 1; // + m_uvOffset.y;
  2751. break;
  2752. case TextureMappingOptions.Line:
  2753. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
  2754. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
  2755. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  2756. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  2757. break;
  2758. case TextureMappingOptions.Paragraph:
  2759. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
  2760. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
  2761. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  2762. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  2763. break;
  2764. case TextureMappingOptions.MatchAspect:
  2765. Debug.Log("ERROR: Cannot Match both Vertical & Horizontal.");
  2766. break;
  2767. }
  2768. //float xDelta = 1 - (_uv2s[vert_index + 0].y * textMeshCharacterInfo[i].AspectRatio); // Left aligned
  2769. float xDelta = (1 - ((characterInfos[i].vertex_BL.uv2.y + characterInfos[i].vertex_TL.uv2.y) * characterInfos[i].aspectRatio)) / 2; // Center of Rectangle
  2770. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
  2771. characterInfos[i].vertex_TL.uv2.x = characterInfos[i].vertex_BL.uv2.x;
  2772. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
  2773. characterInfos[i].vertex_BR.uv2.x = characterInfos[i].vertex_TR.uv2.x;
  2774. break;
  2775. }
  2776. switch (m_verticalMapping)
  2777. {
  2778. case TextureMappingOptions.Character:
  2779. characterInfos[i].vertex_BL.uv2.y = 0; // + m_uvOffset.y;
  2780. characterInfos[i].vertex_TL.uv2.y = 1; // + m_uvOffset.y;
  2781. characterInfos[i].vertex_TR.uv2.y = 1; // + m_uvOffset.y;
  2782. characterInfos[i].vertex_BR.uv2.y = 0; // + m_uvOffset.y;
  2783. break;
  2784. case TextureMappingOptions.Line:
  2785. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineInfo.descender) / (lineInfo.ascender - lineInfo.descender); // + m_uvOffset.y;
  2786. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineInfo.descender) / (lineInfo.ascender - lineInfo.descender); // + m_uvOffset.y;
  2787. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  2788. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  2789. break;
  2790. case TextureMappingOptions.Paragraph:
  2791. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y); // + m_uvOffset.y;
  2792. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y); // + m_uvOffset.y;
  2793. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  2794. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  2795. break;
  2796. case TextureMappingOptions.MatchAspect:
  2797. float yDelta = (1 - ((characterInfos[i].vertex_BL.uv2.x + characterInfos[i].vertex_TR.uv2.x) / characterInfos[i].aspectRatio)) / 2; // Center of Rectangle
  2798. characterInfos[i].vertex_BL.uv2.y = yDelta + (characterInfos[i].vertex_BL.uv2.x / characterInfos[i].aspectRatio); // + m_uvOffset.y;
  2799. characterInfos[i].vertex_TL.uv2.y = yDelta + (characterInfos[i].vertex_TR.uv2.x / characterInfos[i].aspectRatio); // + m_uvOffset.y;
  2800. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  2801. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  2802. break;
  2803. }
  2804. #if TMP_PROFILE_ON
  2805. Profiler.EndSample();
  2806. #endif
  2807. #endregion End UV Mapping Options
  2808. // Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio.
  2809. #region Pack Scale into UV2
  2810. #if TMP_PROFILE_ON
  2811. Profiler.BeginSample("Pack UV");
  2812. #endif
  2813. xScale = characterInfos[i].scale * (1 - m_charWidthAdjDelta);
  2814. if (!characterInfos[i].isUsingAlternateTypeface && (characterInfos[i].style & FontStyles.Bold) == FontStyles.Bold) xScale *= -1;
  2815. switch (canvasRenderMode)
  2816. {
  2817. case RenderMode.ScreenSpaceOverlay:
  2818. xScale *= lossyScale / canvasScaleFactor;
  2819. break;
  2820. case RenderMode.ScreenSpaceCamera:
  2821. xScale *= isCameraAssigned ? lossyScale : 1;
  2822. break;
  2823. case RenderMode.WorldSpace:
  2824. xScale *= lossyScale;
  2825. break;
  2826. }
  2827. // isBold is encoded in the X value and SDF Scale in Y.
  2828. //Vector2 vertexData = new Vector2((characterInfos[i].style & FontStyles.Bold) == FontStyles.Bold ? 1 : 0, xScale);
  2829. //characterInfos[i].vertex_BL.uv2 = vertexData;
  2830. //characterInfos[i].vertex_TL.uv2 = vertexData;
  2831. //characterInfos[i].vertex_TR.uv2 = vertexData;
  2832. //characterInfos[i].vertex_BR.uv2 = vertexData;
  2833. float x0 = characterInfos[i].vertex_BL.uv2.x;
  2834. float y0 = characterInfos[i].vertex_BL.uv2.y;
  2835. float x1 = characterInfos[i].vertex_TR.uv2.x;
  2836. float y1 = characterInfos[i].vertex_TR.uv2.y;
  2837. float dx = (int)x0;
  2838. float dy = (int)y0;
  2839. x0 = x0 - dx;
  2840. x1 = x1 - dx;
  2841. y0 = y0 - dy;
  2842. y1 = y1 - dy;
  2843. // Optimization to avoid having a vector2 returned from the Pack UV function.
  2844. characterInfos[i].vertex_BL.uv2.x = PackUV(x0, y0); characterInfos[i].vertex_BL.uv2.y = xScale;
  2845. characterInfos[i].vertex_TL.uv2.x = PackUV(x0, y1); characterInfos[i].vertex_TL.uv2.y = xScale;
  2846. characterInfos[i].vertex_TR.uv2.x = PackUV(x1, y1); characterInfos[i].vertex_TR.uv2.y = xScale;
  2847. characterInfos[i].vertex_BR.uv2.x = PackUV(x1, y0); characterInfos[i].vertex_BR.uv2.y = xScale;
  2848. #if TMP_PROFILE_ON
  2849. Profiler.EndSample();
  2850. #endif
  2851. #endregion
  2852. break;
  2853. // SPRITES
  2854. case TMP_TextElementType.Sprite:
  2855. // Nothing right now
  2856. break;
  2857. }
  2858. // Handle maxVisibleCharacters, maxVisibleLines and Overflow Page Mode.
  2859. #region Handle maxVisibleCharacters / maxVisibleLines / Page Mode
  2860. #if TMP_PROFILE_ON
  2861. Profiler.BeginSample("Process MaxVisible Characters & Lines");
  2862. #endif
  2863. if (i < m_maxVisibleCharacters && wordCount < m_maxVisibleWords && currentLine < m_maxVisibleLines && m_overflowMode != TextOverflowModes.Page)
  2864. {
  2865. characterInfos[i].vertex_BL.position += offset;
  2866. characterInfos[i].vertex_TL.position += offset;
  2867. characterInfos[i].vertex_TR.position += offset;
  2868. characterInfos[i].vertex_BR.position += offset;
  2869. }
  2870. else if (i < m_maxVisibleCharacters && wordCount < m_maxVisibleWords && currentLine < m_maxVisibleLines && m_overflowMode == TextOverflowModes.Page && characterInfos[i].pageNumber == pageToDisplay)
  2871. {
  2872. characterInfos[i].vertex_BL.position += offset;
  2873. characterInfos[i].vertex_TL.position += offset;
  2874. characterInfos[i].vertex_TR.position += offset;
  2875. characterInfos[i].vertex_BR.position += offset;
  2876. }
  2877. else
  2878. {
  2879. characterInfos[i].vertex_BL.position = Vector3.zero;
  2880. characterInfos[i].vertex_TL.position = Vector3.zero;
  2881. characterInfos[i].vertex_TR.position = Vector3.zero;
  2882. characterInfos[i].vertex_BR.position = Vector3.zero;
  2883. characterInfos[i].isVisible = false;
  2884. }
  2885. #if TMP_PROFILE_ON
  2886. Profiler.EndSample();
  2887. #endif
  2888. #endregion
  2889. // Fill Vertex Buffers for the various types of element
  2890. if (elementType == TMP_TextElementType.Character)
  2891. {
  2892. FillCharacterVertexBuffers(i, vert_index_X4);
  2893. }
  2894. else if (elementType == TMP_TextElementType.Sprite)
  2895. {
  2896. FillSpriteVertexBuffers(i, sprite_index_X4);
  2897. }
  2898. }
  2899. #endregion
  2900. // Apply Alignment and Justification Offset
  2901. m_textInfo.characterInfo[i].bottomLeft += offset;
  2902. m_textInfo.characterInfo[i].topLeft += offset;
  2903. m_textInfo.characterInfo[i].topRight += offset;
  2904. m_textInfo.characterInfo[i].bottomRight += offset;
  2905. m_textInfo.characterInfo[i].origin += offset.x;
  2906. m_textInfo.characterInfo[i].xAdvance += offset.x;
  2907. m_textInfo.characterInfo[i].ascender += offset.y;
  2908. m_textInfo.characterInfo[i].descender += offset.y;
  2909. m_textInfo.characterInfo[i].baseLine += offset.y;
  2910. // Update MeshExtents
  2911. if (isCharacterVisible)
  2912. {
  2913. //m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[i].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[i].bottomLeft.y));
  2914. //m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[i].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[i].topLeft.y));
  2915. }
  2916. // Need to recompute lineExtent to account for the offset from justification.
  2917. #region Adjust lineExtents resulting from alignment offset
  2918. #if TMP_PROFILE_ON
  2919. Profiler.BeginSample("Adjust LineExtents");
  2920. #endif
  2921. if (currentLine != lastLine || i == m_characterCount - 1)
  2922. {
  2923. // Update the previous line's extents
  2924. if (currentLine != lastLine)
  2925. {
  2926. m_textInfo.lineInfo[lastLine].baseline += offset.y;
  2927. m_textInfo.lineInfo[lastLine].ascender += offset.y;
  2928. m_textInfo.lineInfo[lastLine].descender += offset.y;
  2929. m_textInfo.lineInfo[lastLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[lastLine].descender);
  2930. m_textInfo.lineInfo[lastLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[lastLine].ascender);
  2931. }
  2932. // Update the current line's extents
  2933. if (i == m_characterCount - 1)
  2934. {
  2935. m_textInfo.lineInfo[currentLine].baseline += offset.y;
  2936. m_textInfo.lineInfo[currentLine].ascender += offset.y;
  2937. m_textInfo.lineInfo[currentLine].descender += offset.y;
  2938. m_textInfo.lineInfo[currentLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[currentLine].descender);
  2939. m_textInfo.lineInfo[currentLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[currentLine].ascender);
  2940. }
  2941. }
  2942. #if TMP_PROFILE_ON
  2943. Profiler.EndSample();
  2944. #endif
  2945. #endregion
  2946. // Track Word Count per line and for the object
  2947. #region Track Word Count
  2948. #if TMP_PROFILE_ON
  2949. Profiler.BeginSample("Track Word Count");
  2950. #endif
  2951. if (char.IsLetterOrDigit(currentCharacter) || currentCharacter == 0x2D || currentCharacter == 0xAD || currentCharacter == 0x2010 || currentCharacter == 0x2011)
  2952. {
  2953. if (isStartOfWord == false)
  2954. {
  2955. isStartOfWord = true;
  2956. wordFirstChar = i;
  2957. }
  2958. // If last character is a word
  2959. if (isStartOfWord && i == m_characterCount - 1)
  2960. {
  2961. int size = m_textInfo.wordInfo.Length;
  2962. int index = m_textInfo.wordCount;
  2963. if (m_textInfo.wordCount + 1 > size)
  2964. TMP_TextInfo.Resize(ref m_textInfo.wordInfo, size + 1);
  2965. wordLastChar = i;
  2966. m_textInfo.wordInfo[index].firstCharacterIndex = wordFirstChar;
  2967. m_textInfo.wordInfo[index].lastCharacterIndex = wordLastChar;
  2968. m_textInfo.wordInfo[index].characterCount = wordLastChar - wordFirstChar + 1;
  2969. m_textInfo.wordInfo[index].textComponent = this;
  2970. wordCount += 1;
  2971. m_textInfo.wordCount += 1;
  2972. m_textInfo.lineInfo[currentLine].wordCount += 1;
  2973. }
  2974. }
  2975. else if (isStartOfWord || i == 0 && (!char.IsPunctuation(currentCharacter) || char.IsWhiteSpace(currentCharacter) || currentCharacter == 0x200B || i == m_characterCount - 1))
  2976. {
  2977. if (i > 0 && i < characterInfos.Length - 1 && i < m_characterCount && (currentCharacter == 39 || currentCharacter == 8217) && char.IsLetterOrDigit(characterInfos[i - 1].character) && char.IsLetterOrDigit(characterInfos[i + 1].character))
  2978. {
  2979. }
  2980. else
  2981. {
  2982. wordLastChar = i == m_characterCount - 1 && char.IsLetterOrDigit(currentCharacter) ? i : i - 1;
  2983. isStartOfWord = false;
  2984. int size = m_textInfo.wordInfo.Length;
  2985. int index = m_textInfo.wordCount;
  2986. if (m_textInfo.wordCount + 1 > size)
  2987. TMP_TextInfo.Resize(ref m_textInfo.wordInfo, size + 1);
  2988. m_textInfo.wordInfo[index].firstCharacterIndex = wordFirstChar;
  2989. m_textInfo.wordInfo[index].lastCharacterIndex = wordLastChar;
  2990. m_textInfo.wordInfo[index].characterCount = wordLastChar - wordFirstChar + 1;
  2991. m_textInfo.wordInfo[index].textComponent = this;
  2992. wordCount += 1;
  2993. m_textInfo.wordCount += 1;
  2994. m_textInfo.lineInfo[currentLine].wordCount += 1;
  2995. }
  2996. }
  2997. #if TMP_PROFILE_ON
  2998. Profiler.EndSample();
  2999. #endif
  3000. #endregion
  3001. // Setup & Handle Underline
  3002. #region Underline
  3003. #if TMP_PROFILE_ON
  3004. Profiler.BeginSample("Process Underline & Strikethrough");
  3005. #endif
  3006. // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
  3007. bool isUnderline = (m_textInfo.characterInfo[i].style & FontStyles.Underline) == FontStyles.Underline;
  3008. if (isUnderline)
  3009. {
  3010. bool isUnderlineVisible = true;
  3011. int currentPage = m_textInfo.characterInfo[i].pageNumber;
  3012. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
  3013. isUnderlineVisible = false;
  3014. // We only use the scale of visible characters.
  3015. if (!char.IsWhiteSpace(currentCharacter) && currentCharacter != 0x200B)
  3016. {
  3017. underlineMaxScale = Mathf.Max(underlineMaxScale, m_textInfo.characterInfo[i].scale);
  3018. underlineBaseLine = Mathf.Min(currentPage == lastPage ? underlineBaseLine : k_LargePositiveFloat, m_textInfo.characterInfo[i].baseLine + font.fontInfo.Underline * underlineMaxScale);
  3019. lastPage = currentPage; // Need to track pages to ensure we reset baseline for the new pages.
  3020. }
  3021. if (beginUnderline == false && isUnderlineVisible == true && i <= lineInfo.lastVisibleCharacterIndex && currentCharacter != 10 && currentCharacter != 13)
  3022. {
  3023. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(currentCharacter))
  3024. { }
  3025. else
  3026. {
  3027. beginUnderline = true;
  3028. underlineStartScale = m_textInfo.characterInfo[i].scale;
  3029. if (underlineMaxScale == 0) underlineMaxScale = underlineStartScale;
  3030. underline_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, underlineBaseLine, 0);
  3031. underlineColor = m_textInfo.characterInfo[i].underlineColor;
  3032. }
  3033. }
  3034. // End Underline if text only contains one character.
  3035. if (beginUnderline && m_characterCount == 1)
  3036. {
  3037. beginUnderline = false;
  3038. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  3039. underlineEndScale = m_textInfo.characterInfo[i].scale;
  3040. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScale, underlineColor);
  3041. underlineMaxScale = 0;
  3042. underlineBaseLine = k_LargePositiveFloat;
  3043. }
  3044. else if (beginUnderline && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
  3045. {
  3046. // Terminate underline at previous visible character if space or carriage return.
  3047. if (char.IsWhiteSpace(currentCharacter) || currentCharacter == 0x200B)
  3048. {
  3049. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  3050. underline_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, underlineBaseLine, 0);
  3051. underlineEndScale = m_textInfo.characterInfo[lastVisibleCharacterIndex].scale;
  3052. }
  3053. else
  3054. { // End underline if last character of the line.
  3055. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  3056. underlineEndScale = m_textInfo.characterInfo[i].scale;
  3057. }
  3058. beginUnderline = false;
  3059. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScale, underlineColor);
  3060. underlineMaxScale = 0;
  3061. underlineBaseLine = k_LargePositiveFloat;
  3062. }
  3063. else if (beginUnderline && !isUnderlineVisible)
  3064. {
  3065. beginUnderline = false;
  3066. underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
  3067. underlineEndScale = m_textInfo.characterInfo[i - 1].scale;
  3068. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScale, underlineColor);
  3069. underlineMaxScale = 0;
  3070. underlineBaseLine = k_LargePositiveFloat;
  3071. }
  3072. else if (beginUnderline && i < m_characterCount - 1 && !underlineColor.Compare(m_textInfo.characterInfo[i + 1].underlineColor))
  3073. {
  3074. // End underline if underline color has changed.
  3075. beginUnderline = false;
  3076. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  3077. underlineEndScale = m_textInfo.characterInfo[i].scale;
  3078. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScale, underlineColor);
  3079. underlineMaxScale = 0;
  3080. underlineBaseLine = k_LargePositiveFloat;
  3081. }
  3082. }
  3083. else
  3084. {
  3085. // End Underline
  3086. if (beginUnderline == true)
  3087. {
  3088. beginUnderline = false;
  3089. underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
  3090. underlineEndScale = m_textInfo.characterInfo[i - 1].scale;
  3091. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScale, underlineColor);
  3092. underlineMaxScale = 0;
  3093. underlineBaseLine = k_LargePositiveFloat;
  3094. }
  3095. }
  3096. #endregion
  3097. // Setup & Handle Strikethrough
  3098. #region Strikethrough
  3099. // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
  3100. bool isStrikethrough = (m_textInfo.characterInfo[i].style & FontStyles.Strikethrough) == FontStyles.Strikethrough;
  3101. float strikethroughOffset = currentFontAsset.fontInfo.strikethrough;
  3102. if (isStrikethrough)
  3103. {
  3104. bool isStrikeThroughVisible = true;
  3105. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && m_textInfo.characterInfo[i].pageNumber + 1 != m_pageToDisplay))
  3106. isStrikeThroughVisible = false;
  3107. if (beginStrikethrough == false && isStrikeThroughVisible && i <= lineInfo.lastVisibleCharacterIndex && currentCharacter != 10 && currentCharacter != 13)
  3108. {
  3109. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(currentCharacter))
  3110. { }
  3111. else
  3112. {
  3113. beginStrikethrough = true;
  3114. strikethroughPointSize = m_textInfo.characterInfo[i].pointSize;
  3115. strikethroughScale = m_textInfo.characterInfo[i].scale;
  3116. strikethrough_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3117. strikethroughColor = m_textInfo.characterInfo[i].strikethroughColor;
  3118. strikethroughBaseline = m_textInfo.characterInfo[i].baseLine;
  3119. //Debug.Log("Char [" + currentCharacter + "] Start Strikethrough POS: " + strikethrough_start);
  3120. }
  3121. }
  3122. // End Strikethrough if text only contains one character.
  3123. if (beginStrikethrough && m_characterCount == 1)
  3124. {
  3125. beginStrikethrough = false;
  3126. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3127. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3128. }
  3129. else if (beginStrikethrough && i == lineInfo.lastCharacterIndex)
  3130. {
  3131. // Terminate Strikethrough at previous visible character if space or carriage return.
  3132. if (char.IsWhiteSpace(currentCharacter) || currentCharacter == 0x200B)
  3133. {
  3134. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  3135. strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + strikethroughOffset * strikethroughScale, 0);
  3136. }
  3137. else
  3138. {
  3139. // Terminate Strikethrough at last character of line.
  3140. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3141. }
  3142. beginStrikethrough = false;
  3143. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3144. }
  3145. else if (beginStrikethrough && i < m_characterCount && (m_textInfo.characterInfo[i + 1].pointSize != strikethroughPointSize || !TMP_Math.Approximately(m_textInfo.characterInfo[i + 1].baseLine + offset.y, strikethroughBaseline)))
  3146. {
  3147. // Terminate Strikethrough if scale changes.
  3148. beginStrikethrough = false;
  3149. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  3150. if (i > lastVisibleCharacterIndex)
  3151. strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + strikethroughOffset * strikethroughScale, 0);
  3152. else
  3153. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3154. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3155. //Debug.Log("Char [" + currentCharacter + "] at Index: " + i + " End Strikethrough POS: " + strikethrough_end + " Baseline: " + m_textInfo.characterInfo[i].baseLine.ToString("f3"));
  3156. }
  3157. else if (beginStrikethrough && i < m_characterCount && currentFontAsset.GetInstanceID() != characterInfos[i + 1].fontAsset.GetInstanceID())
  3158. {
  3159. // Terminate Strikethrough if font asset changes.
  3160. beginStrikethrough = false;
  3161. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  3162. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3163. }
  3164. else if (beginStrikethrough && !isStrikeThroughVisible)
  3165. {
  3166. // Terminate Strikethrough if character is not visible.
  3167. beginStrikethrough = false;
  3168. strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + strikethroughOffset * strikethroughScale, 0);
  3169. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3170. }
  3171. }
  3172. else
  3173. {
  3174. // End Strikethrough
  3175. if (beginStrikethrough == true)
  3176. {
  3177. beginStrikethrough = false;
  3178. strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + strikethroughOffset * strikethroughScale, 0);
  3179. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  3180. }
  3181. }
  3182. #endregion
  3183. // HANDLE TEXT HIGHLIGHTING
  3184. #region Text Highlighting
  3185. bool isHighlight = (m_textInfo.characterInfo[i].style & FontStyles.Highlight) == FontStyles.Highlight;
  3186. if (isHighlight)
  3187. {
  3188. bool isHighlightVisible = true;
  3189. int currentPage = m_textInfo.characterInfo[i].pageNumber;
  3190. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
  3191. isHighlightVisible = false;
  3192. if (beginHighlight == false && isHighlightVisible == true && i <= lineInfo.lastVisibleCharacterIndex && currentCharacter != 10 && currentCharacter != 13)
  3193. {
  3194. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(currentCharacter))
  3195. { }
  3196. else
  3197. {
  3198. beginHighlight = true;
  3199. highlight_start = k_LargePositiveVector2;
  3200. highlight_end = k_LargeNegativeVector2;
  3201. highlightColor = m_textInfo.characterInfo[i].highlightColor;
  3202. }
  3203. }
  3204. if (beginHighlight)
  3205. {
  3206. Color32 currentHighlightColor = m_textInfo.characterInfo[i].highlightColor;
  3207. bool isColorTransition = false;
  3208. // Handle Highlight color changes
  3209. if (!highlightColor.Compare(currentHighlightColor))
  3210. {
  3211. // End drawing at the start of new highlight color to prevent a gap between highlight sections.
  3212. highlight_end.x = (highlight_end.x + m_textInfo.characterInfo[i].bottomLeft.x) / 2;
  3213. highlight_start.y = Mathf.Min(highlight_start.y, m_textInfo.characterInfo[i].descender);
  3214. highlight_end.y = Mathf.Max(highlight_end.y, m_textInfo.characterInfo[i].ascender);
  3215. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightColor);
  3216. beginHighlight = true;
  3217. highlight_start = highlight_end;
  3218. highlight_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].descender, 0);
  3219. highlightColor = m_textInfo.characterInfo[i].highlightColor;
  3220. isColorTransition = true;
  3221. }
  3222. if (!isColorTransition)
  3223. {
  3224. // Use the Min / Max Extents of the Highlight area to handle different character sizes and fonts.
  3225. highlight_start.x = Mathf.Min(highlight_start.x, m_textInfo.characterInfo[i].bottomLeft.x);
  3226. highlight_start.y = Mathf.Min(highlight_start.y, m_textInfo.characterInfo[i].descender);
  3227. highlight_end.x = Mathf.Max(highlight_end.x, m_textInfo.characterInfo[i].topRight.x);
  3228. highlight_end.y = Mathf.Max(highlight_end.y, m_textInfo.characterInfo[i].ascender);
  3229. }
  3230. }
  3231. // End Highlight if text only contains one character.
  3232. if (beginHighlight && m_characterCount == 1)
  3233. {
  3234. beginHighlight = false;
  3235. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightColor);
  3236. }
  3237. else if (beginHighlight && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
  3238. {
  3239. beginHighlight = false;
  3240. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightColor);
  3241. }
  3242. else if (beginHighlight && !isHighlightVisible)
  3243. {
  3244. beginHighlight = false;
  3245. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightColor);
  3246. }
  3247. }
  3248. else
  3249. {
  3250. // End Highlight
  3251. if (beginHighlight == true)
  3252. {
  3253. beginHighlight = false;
  3254. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightColor);
  3255. }
  3256. }
  3257. #endregion
  3258. #if TMP_PROFILE_ON
  3259. Profiler.EndSample();
  3260. #endif
  3261. #endregion
  3262. lastLine = currentLine;
  3263. }
  3264. #endregion
  3265. // METRICS ABOUT THE TEXT OBJECT
  3266. m_textInfo.characterCount = m_characterCount;
  3267. m_textInfo.spriteCount = m_spriteCount;
  3268. m_textInfo.lineCount = lineCount;
  3269. m_textInfo.wordCount = wordCount != 0 && m_characterCount > 0 ? wordCount : 1;
  3270. m_textInfo.pageCount = m_pageNumber + 1;
  3271. #if TMP_PROFILE_PHASES_ON
  3272. Profiler.EndSample();
  3273. #endif
  3274. // *** UPLOAD MESH DATA ***
  3275. #if TMP_PROFILE_PHASES_ON
  3276. Profiler.BeginSample("TMP Generate Text - Phase III");
  3277. #endif
  3278. if (m_renderMode == TextRenderFlags.Render && IsActive())
  3279. {
  3280. // Clear unused vertices
  3281. //m_textInfo.meshInfo[0].ClearUnusedVertices();
  3282. // Must ensure the Canvas support the additon vertex attributes used by TMP.
  3283. if (m_canvas.additionalShaderChannels != (AdditionalCanvasShaderChannels)25)
  3284. m_canvas.additionalShaderChannels |= (AdditionalCanvasShaderChannels)25;
  3285. // Sort the geometry of the text object if needed.
  3286. if (m_geometrySortingOrder != VertexSortingOrder.Normal)
  3287. m_textInfo.meshInfo[0].SortGeometry(VertexSortingOrder.Reverse);
  3288. // Upload Mesh Data
  3289. m_mesh.MarkDynamic();
  3290. m_mesh.vertices = m_textInfo.meshInfo[0].vertices;
  3291. m_mesh.uv = m_textInfo.meshInfo[0].uvs0;
  3292. m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
  3293. //m_mesh.uv4 = m_textInfo.meshInfo[0].uvs4;
  3294. m_mesh.colors32 = m_textInfo.meshInfo[0].colors32;
  3295. // Compute Bounds for the mesh. Manual computation is more efficient then using Mesh.recalcualteBounds.
  3296. m_mesh.RecalculateBounds();
  3297. //m_mesh.bounds = new Bounds(new Vector3((m_meshExtents.max.x + m_meshExtents.min.x) / 2, (m_meshExtents.max.y + m_meshExtents.min.y) / 2, 0) + offset, new Vector3(m_meshExtents.max.x - m_meshExtents.min.x, m_meshExtents.max.y - m_meshExtents.min.y, 0));
  3298. m_canvasRenderer.SetMesh(m_mesh);
  3299. // Cache CanvasRenderer color of the parent text object.
  3300. Color parentBaseColor = m_canvasRenderer.GetColor();
  3301. for (int i = 1; i < m_textInfo.materialCount; i++)
  3302. {
  3303. // Clear unused vertices
  3304. m_textInfo.meshInfo[i].ClearUnusedVertices();
  3305. if (m_subTextObjects[i] == null) continue;
  3306. // Sort the geometry of the sub-text objects if needed.
  3307. if (m_geometrySortingOrder != VertexSortingOrder.Normal)
  3308. m_textInfo.meshInfo[i].SortGeometry(VertexSortingOrder.Reverse);
  3309. //m_subTextObjects[i].mesh.MarkDynamic();
  3310. m_subTextObjects[i].mesh.vertices = m_textInfo.meshInfo[i].vertices;
  3311. m_subTextObjects[i].mesh.uv = m_textInfo.meshInfo[i].uvs0;
  3312. m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  3313. //m_subTextObjects[i].mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  3314. m_subTextObjects[i].mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  3315. m_subTextObjects[i].mesh.RecalculateBounds();
  3316. m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  3317. // Set CanvasRenderer color to match the parent text object.
  3318. m_subTextObjects[i].canvasRenderer.SetColor(parentBaseColor);
  3319. }
  3320. }
  3321. // Event indicating the text has been regenerated.
  3322. TMPro_EventManager.ON_TEXT_CHANGED(this);
  3323. //SendOnTextChanged();
  3324. #if TMP_PROFILE_PHASES_ON
  3325. Profiler.EndSample();
  3326. #endif
  3327. //Debug.Log("Done Rendering Text.");
  3328. }
  3329. /// <summary>
  3330. /// Method to return the local corners of the Text Container or RectTransform.
  3331. /// </summary>
  3332. /// <returns></returns>
  3333. protected override Vector3[] GetTextContainerLocalCorners()
  3334. {
  3335. if (m_rectTransform == null) m_rectTransform = this.rectTransform;
  3336. m_rectTransform.GetLocalCorners(m_RectTransformCorners);
  3337. return m_RectTransformCorners;
  3338. }
  3339. /// <summary>
  3340. /// Method to Enable or Disable child SubMesh objects.
  3341. /// </summary>
  3342. /// <param name="state"></param>
  3343. protected override void SetActiveSubMeshes(bool state)
  3344. {
  3345. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  3346. {
  3347. if (m_subTextObjects[i].enabled != state)
  3348. m_subTextObjects[i].enabled = state;
  3349. }
  3350. }
  3351. /// <summary>
  3352. /// Method returning the compound bounds of the text object and child sub objects.
  3353. /// </summary>
  3354. /// <returns></returns>
  3355. protected override Bounds GetCompoundBounds()
  3356. {
  3357. Bounds mainBounds = m_mesh.bounds;
  3358. Vector3 min = mainBounds.min;
  3359. Vector3 max = mainBounds.max;
  3360. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  3361. {
  3362. Bounds subBounds = m_subTextObjects[i].mesh.bounds;
  3363. min.x = min.x < subBounds.min.x ? min.x : subBounds.min.x;
  3364. min.y = min.y < subBounds.min.y ? min.y : subBounds.min.y;
  3365. max.x = max.x > subBounds.max.x ? max.x : subBounds.max.x;
  3366. max.y = max.y > subBounds.max.y ? max.y : subBounds.max.y;
  3367. }
  3368. Vector3 center = (min + max) / 2;
  3369. Vector2 size = max - min;
  3370. return new Bounds(center, size);
  3371. }
  3372. //public override void UpdateGeometry()
  3373. //{
  3374. //}
  3375. /// <summary>
  3376. /// Method to Update Scale in UV2
  3377. /// </summary>
  3378. void UpdateSDFScale(float lossyScale)
  3379. {
  3380. //Debug.Log("Updating SDF Scale.");
  3381. // Return if we don't have a valid reference to a Canvas.
  3382. if (m_canvas == null)
  3383. {
  3384. m_canvas = GetCanvas();
  3385. if (m_canvas == null) return;
  3386. }
  3387. lossyScale = lossyScale == 0 ? 1 : lossyScale;
  3388. float xScale = 0;
  3389. float canvasScaleFactor = m_canvas.scaleFactor;
  3390. if (m_canvas.renderMode == RenderMode.ScreenSpaceOverlay)
  3391. xScale = lossyScale / canvasScaleFactor;
  3392. else if (m_canvas.renderMode == RenderMode.ScreenSpaceCamera)
  3393. xScale = m_canvas.worldCamera != null ? lossyScale : 1;
  3394. else
  3395. xScale = lossyScale;
  3396. // Iterate through each of the characters.
  3397. for (int i = 0; i < m_textInfo.characterCount; i++)
  3398. {
  3399. // Only update scale for visible characters.
  3400. if (m_textInfo.characterInfo[i].isVisible && m_textInfo.characterInfo[i].elementType == TMP_TextElementType.Character)
  3401. {
  3402. float scale = xScale * m_textInfo.characterInfo[i].scale * (1 - m_charWidthAdjDelta);
  3403. if (!m_textInfo.characterInfo[i].isUsingAlternateTypeface && (m_textInfo.characterInfo[i].style & FontStyles.Bold) == FontStyles.Bold) scale *= -1;
  3404. int index = m_textInfo.characterInfo[i].materialReferenceIndex;
  3405. int vertexIndex = m_textInfo.characterInfo[i].vertexIndex;
  3406. m_textInfo.meshInfo[index].uvs2[vertexIndex + 0].y = scale;
  3407. m_textInfo.meshInfo[index].uvs2[vertexIndex + 1].y = scale;
  3408. m_textInfo.meshInfo[index].uvs2[vertexIndex + 2].y = scale;
  3409. m_textInfo.meshInfo[index].uvs2[vertexIndex + 3].y = scale;
  3410. }
  3411. }
  3412. // Push the updated uv2 scale information to the meshes.
  3413. for (int i = 0; i < m_textInfo.materialCount; i++)
  3414. {
  3415. if (i == 0)
  3416. {
  3417. m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
  3418. m_canvasRenderer.SetMesh(m_mesh);
  3419. }
  3420. else
  3421. {
  3422. m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  3423. m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  3424. }
  3425. }
  3426. }
  3427. // Function to offset vertices position to account for line spacing changes.
  3428. protected override void AdjustLineOffset(int startIndex, int endIndex, float offset)
  3429. {
  3430. Vector3 vertexOffset = new Vector3(0, offset, 0);
  3431. for (int i = startIndex; i <= endIndex; i++)
  3432. {
  3433. m_textInfo.characterInfo[i].bottomLeft -= vertexOffset;
  3434. m_textInfo.characterInfo[i].topLeft -= vertexOffset;
  3435. m_textInfo.characterInfo[i].topRight -= vertexOffset;
  3436. m_textInfo.characterInfo[i].bottomRight -= vertexOffset;
  3437. m_textInfo.characterInfo[i].ascender -= vertexOffset.y;
  3438. m_textInfo.characterInfo[i].baseLine -= vertexOffset.y;
  3439. m_textInfo.characterInfo[i].descender -= vertexOffset.y;
  3440. if (m_textInfo.characterInfo[i].isVisible)
  3441. {
  3442. m_textInfo.characterInfo[i].vertex_BL.position -= vertexOffset;
  3443. m_textInfo.characterInfo[i].vertex_TL.position -= vertexOffset;
  3444. m_textInfo.characterInfo[i].vertex_TR.position -= vertexOffset;
  3445. m_textInfo.characterInfo[i].vertex_BR.position -= vertexOffset;
  3446. }
  3447. }
  3448. }
  3449. }
  3450. }