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