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