2022-01-12 10:06:03 +03:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
2022-01-12 10:39:15 +03:00
using Unity.Profiling ;
using UnityEngine ;
using UnityEngine.TextCore ;
2022-01-12 10:06:03 +03:00
using Object = UnityEngine . Object ;
#pragma warning disable 0414 // Disabled a few warnings related to serialized variables not used in this script but used in the editor.
namespace TMPro
{
public partial class TextMeshPro
{
[SerializeField]
private bool m_hasFontAssetChanged = false ; // Used to track when font properties have changed.
float m_previousLossyScaleY = - 1 ; // Used for Tracking lossy scale changes in the transform;
[SerializeField]
private Renderer m_renderer ;
private MeshFilter m_meshFilter ;
private bool m_isFirstAllocation ; // Flag to determine if this is the first allocation of the buffers.
private int m_max_characters = 8 ; // Determines the initial allocation and size of the character array / buffer.
private int m_max_numberOfLines = 4 ; // Determines the initial allocation and maximum number of lines of text.
private TMP_SubMesh [ ] m_subTextObjects = new TMP_SubMesh [ 8 ] ;
// MASKING RELATED PROPERTIES
[SerializeField]
private MaskingTypes m_maskType ;
// Matrix used to animated Env Map
private Matrix4x4 m_EnvMapMatrix = new Matrix4x4 ( ) ;
// Text Container / RectTransform Component
private Vector3 [ ] m_RectTransformCorners = new Vector3 [ 4 ] ;
[NonSerialized]
private bool m_isRegisteredForEvents ;
2022-01-12 10:39:15 +03:00
// Profiler Marker declarations
private static ProfilerMarker k_GenerateTextMarker = new ProfilerMarker ( "TMP Layout Text" ) ;
private static ProfilerMarker k_SetArraySizesMarker = new ProfilerMarker ( "TMP.SetArraySizes" ) ;
private static ProfilerMarker k_GenerateTextPhaseIMarker = new ProfilerMarker ( "TMP GenerateText - Phase I" ) ;
private static ProfilerMarker k_ParseMarkupTextMarker = new ProfilerMarker ( "TMP Parse Markup Text" ) ;
private static ProfilerMarker k_CharacterLookupMarker = new ProfilerMarker ( "TMP Lookup Character & Glyph Data" ) ;
private static ProfilerMarker k_HandleGPOSFeaturesMarker = new ProfilerMarker ( "TMP Handle GPOS Features" ) ;
private static ProfilerMarker k_CalculateVerticesPositionMarker = new ProfilerMarker ( "TMP Calculate Vertices Position" ) ;
private static ProfilerMarker k_ComputeTextMetricsMarker = new ProfilerMarker ( "TMP Compute Text Metrics" ) ;
private static ProfilerMarker k_HandleVisibleCharacterMarker = new ProfilerMarker ( "TMP Handle Visible Character" ) ;
private static ProfilerMarker k_HandleWhiteSpacesMarker = new ProfilerMarker ( "TMP Handle White Space & Control Character" ) ;
private static ProfilerMarker k_HandleHorizontalLineBreakingMarker = new ProfilerMarker ( "TMP Handle Horizontal Line Breaking" ) ;
private static ProfilerMarker k_HandleVerticalLineBreakingMarker = new ProfilerMarker ( "TMP Handle Vertical Line Breaking" ) ;
private static ProfilerMarker k_SaveGlyphVertexDataMarker = new ProfilerMarker ( "TMP Save Glyph Vertex Data" ) ;
private static ProfilerMarker k_ComputeCharacterAdvanceMarker = new ProfilerMarker ( "TMP Compute Character Advance" ) ;
private static ProfilerMarker k_HandleCarriageReturnMarker = new ProfilerMarker ( "TMP Handle Carriage Return" ) ;
private static ProfilerMarker k_HandleLineTerminationMarker = new ProfilerMarker ( "TMP Handle Line Termination" ) ;
private static ProfilerMarker k_SavePageInfoMarker = new ProfilerMarker ( "TMP Save Text Extent & Page Info" ) ;
private static ProfilerMarker k_SaveProcessingStatesMarker = new ProfilerMarker ( "TMP Save Processing States" ) ;
private static ProfilerMarker k_GenerateTextPhaseIIMarker = new ProfilerMarker ( "TMP GenerateText - Phase II" ) ;
private static ProfilerMarker k_GenerateTextPhaseIIIMarker = new ProfilerMarker ( "TMP GenerateText - Phase III" ) ;
2022-01-12 10:06:03 +03:00
protected override void Awake ( )
{
//Debug.Log("***** Awake() called on object ID " + GetInstanceID() + ". *****");
#if UNITY_EDITOR
// Special handling for TMP Settings and importing Essential Resources
if ( TMP_Settings . instance = = null )
{
if ( m_isWaitingOnResourceLoad = = false )
TMPro_EventManager . RESOURCE_LOAD_EVENT . Add ( ON_RESOURCES_LOADED ) ;
m_isWaitingOnResourceLoad = true ;
return ;
}
#endif
// Cache Reference to the Mesh Renderer.
m_renderer = GetComponent < Renderer > ( ) ;
if ( m_renderer = = null )
m_renderer = gameObject . AddComponent < Renderer > ( ) ;
// Cache Reference to RectTransform
m_rectTransform = this . rectTransform ;
// Cache Reference to the transform;
m_transform = this . transform ;
// Cache a reference to the Mesh Filter.
m_meshFilter = GetComponent < MeshFilter > ( ) ;
if ( m_meshFilter = = null )
m_meshFilter = gameObject . AddComponent < MeshFilter > ( ) ;
// Create new Mesh if necessary and cache reference to it.
if ( m_mesh = = null )
{
m_mesh = new Mesh ( ) ;
m_mesh . hideFlags = HideFlags . HideAndDontSave ;
#if DEVELOPMENT_BUILD | | UNITY_EDITOR
m_mesh . name = "TextMeshPro Mesh" ;
#endif
m_meshFilter . sharedMesh = m_mesh ;
// Create new TextInfo for the text object.
m_textInfo = new TMP_TextInfo ( this ) ;
}
m_meshFilter . hideFlags = HideFlags . HideInInspector | HideFlags . HideAndDontSave ;
2022-01-12 10:39:15 +03:00
#if UNITY_EDITOR
// Special handling for the CanvasRenderer which used to be automatically added by the Graphic class.
CanvasRenderer canvasRendererComponent = GetComponent < CanvasRenderer > ( ) ;
if ( canvasRendererComponent ! = null )
{
Debug . LogWarning ( "Please remove the CanvasRenderer component from the [" + this . name + "] GameObject as this component is no longer necessary." , this ) ;
canvasRendererComponent . hideFlags = HideFlags . None ;
}
#endif
2022-01-12 10:06:03 +03:00
// Load TMP Settings for new text object instances.
LoadDefaultSettings ( ) ;
// Load the font asset and assign material to renderer.
LoadFontAsset ( ) ;
// Allocate our initial buffers.
2022-01-12 10:39:15 +03:00
if ( m_TextProcessingArray = = null )
m_TextProcessingArray = new UnicodeChar [ m_max_characters ] ;
2022-01-12 10:06:03 +03:00
m_cached_TextElement = new TMP_Character ( ) ;
m_isFirstAllocation = true ;
// Check to make sure Sub Text Objects are tracked correctly in the event a Prefab is used.
TMP_SubMesh [ ] subTextObjects = GetComponentsInChildren < TMP_SubMesh > ( ) ;
if ( subTextObjects . Length > 0 )
{
2022-01-12 10:39:15 +03:00
int subTextObjectCount = subTextObjects . Length ;
if ( subTextObjectCount + 1 > m_subTextObjects . Length )
Array . Resize ( ref m_subTextObjects , subTextObjectCount + 1 ) ;
for ( int i = 0 ; i < subTextObjectCount ; i + + )
2022-01-12 10:06:03 +03:00
m_subTextObjects [ i + 1 ] = subTextObjects [ i ] ;
}
// Set flags to ensure our text is parsed and redrawn.
m_havePropertiesChanged = true ;
m_isAwake = true ;
}
protected override void OnEnable ( )
{
//Debug.Log("***** OnEnable() called on object ID " + GetInstanceID() + ". *****");
// Return if Awake() has not been called on the text object.
if ( m_isAwake = = false )
return ;
// Register Callbacks for various events.
if ( ! m_isRegisteredForEvents )
{
#if UNITY_EDITOR
TMPro_EventManager . MATERIAL_PROPERTY_EVENT . Add ( ON_MATERIAL_PROPERTY_CHANGED ) ;
TMPro_EventManager . FONT_PROPERTY_EVENT . Add ( ON_FONT_PROPERTY_CHANGED ) ;
TMPro_EventManager . TEXTMESHPRO_PROPERTY_EVENT . Add ( ON_TEXTMESHPRO_PROPERTY_CHANGED ) ;
TMPro_EventManager . DRAG_AND_DROP_MATERIAL_EVENT . Add ( ON_DRAG_AND_DROP_MATERIAL ) ;
TMPro_EventManager . TEXT_STYLE_PROPERTY_EVENT . Add ( ON_TEXT_STYLE_CHANGED ) ;
TMPro_EventManager . COLOR_GRADIENT_PROPERTY_EVENT . Add ( ON_COLOR_GRADIENT_CHANGED ) ;
TMPro_EventManager . TMP_SETTINGS_PROPERTY_EVENT . Add ( ON_TMP_SETTINGS_CHANGED ) ;
UnityEditor . PrefabUtility . prefabInstanceUpdated + = OnPrefabInstanceUpdate ;
#endif
m_isRegisteredForEvents = true ;
}
// Register text object for internal updates
if ( m_IsTextObjectScaleStatic = = false )
TMP_UpdateManager . RegisterTextObjectForUpdate ( this ) ;
meshFilter . sharedMesh = mesh ;
SetActiveSubMeshes ( true ) ;
// Schedule potential text object update (if any of the properties have changed.
ComputeMarginSize ( ) ;
SetAllDirty ( ) ;
//m_havePropertiesChanged = true;
}
protected override void OnDisable ( )
{
//Debug.Log("***** OnDisable() called on object ID " + GetInstanceID() + ". *****");
// Return if Awake() has not been called on the text object.
if ( m_isAwake = = false )
return ;
TMP_UpdateManager . UnRegisterTextElementForRebuild ( this ) ;
TMP_UpdateManager . UnRegisterTextObjectForUpdate ( this ) ;
meshFilter . sharedMesh = null ;
SetActiveSubMeshes ( false ) ;
}
protected override void OnDestroy ( )
{
//Debug.Log("***** OnDestroy() called on object ID " + GetInstanceID() + ". *****");
// Destroy the mesh if we have one.
if ( m_mesh ! = null )
DestroyImmediate ( m_mesh ) ;
// Unregister the event this object was listening to
#if UNITY_EDITOR
TMPro_EventManager . MATERIAL_PROPERTY_EVENT . Remove ( ON_MATERIAL_PROPERTY_CHANGED ) ;
TMPro_EventManager . FONT_PROPERTY_EVENT . Remove ( ON_FONT_PROPERTY_CHANGED ) ;
TMPro_EventManager . TEXTMESHPRO_PROPERTY_EVENT . Remove ( ON_TEXTMESHPRO_PROPERTY_CHANGED ) ;
TMPro_EventManager . DRAG_AND_DROP_MATERIAL_EVENT . Remove ( ON_DRAG_AND_DROP_MATERIAL ) ;
TMPro_EventManager . TEXT_STYLE_PROPERTY_EVENT . Remove ( ON_TEXT_STYLE_CHANGED ) ;
TMPro_EventManager . COLOR_GRADIENT_PROPERTY_EVENT . Remove ( ON_COLOR_GRADIENT_CHANGED ) ;
TMPro_EventManager . TMP_SETTINGS_PROPERTY_EVENT . Remove ( ON_TMP_SETTINGS_CHANGED ) ;
TMPro_EventManager . RESOURCE_LOAD_EVENT . Remove ( ON_RESOURCES_LOADED ) ;
UnityEditor . PrefabUtility . prefabInstanceUpdated - = OnPrefabInstanceUpdate ;
#endif
m_isRegisteredForEvents = false ;
TMP_UpdateManager . UnRegisterTextElementForRebuild ( this ) ;
TMP_UpdateManager . UnRegisterTextObjectForUpdate ( this ) ;
}
#if UNITY_EDITOR
protected override void Reset ( )
{
//Debug.Log("***** Reset() called on object ID " + GetInstanceID() + ". *****");
// Return if Awake() has not been called on the text object.
if ( m_isAwake = = false )
return ;
if ( m_mesh ! = null )
DestroyImmediate ( m_mesh ) ;
Awake ( ) ;
}
protected override void OnValidate ( )
{
//Debug.Log("***** OnValidate() called on object ID " + GetInstanceID() + ". *****", this);
if ( m_isAwake = = false )
return ;
if ( meshFilter ! = null & & m_meshFilter . hideFlags ! = ( HideFlags . HideInInspector | HideFlags . HideAndDontSave ) )
m_meshFilter . hideFlags = HideFlags . HideInInspector | HideFlags . HideAndDontSave ;
// Handle Font Asset changes in the inspector
if ( m_fontAsset = = null | | m_hasFontAssetChanged )
{
LoadFontAsset ( ) ;
m_hasFontAssetChanged = false ;
}
m_padding = GetPaddingForMaterial ( ) ;
ComputeMarginSize ( ) ;
2022-01-12 10:39:15 +03:00
m_inputSource = TextInputSources . TextInputBox ;
2022-01-12 10:06:03 +03:00
m_havePropertiesChanged = true ;
m_isPreferredWidthDirty = true ;
m_isPreferredHeightDirty = true ;
SetAllDirty ( ) ;
}
private void OnBecameVisible ( )
{
// Keep the parent text object's renderer in sync with child sub objects' renderers.
SetActiveSubTextObjectRenderers ( true ) ;
}
private void OnBecameInvisible ( )
{
2022-01-12 10:39:15 +03:00
// Keep the parent text object's renderer in sync with child sub objects' renderers.
2022-01-12 10:06:03 +03:00
SetActiveSubTextObjectRenderers ( false ) ;
}
/// <summary>
/// Callback received when Prefabs are updated.
/// </summary>
/// <param name="go">The affected GameObject</param>
void OnPrefabInstanceUpdate ( GameObject go )
{
// Remove Callback if this prefab has been deleted.
if ( this = = null )
{
UnityEditor . PrefabUtility . prefabInstanceUpdated - = OnPrefabInstanceUpdate ;
return ;
}
if ( go = = this . gameObject )
{
TMP_SubMesh [ ] subTextObjects = GetComponentsInChildren < TMP_SubMesh > ( ) ;
if ( subTextObjects . Length > 0 )
{
for ( int i = 0 ; i < subTextObjects . Length ; i + + )
m_subTextObjects [ i + 1 ] = subTextObjects [ i ] ;
}
}
}
// Event received when TMP resources have been loaded.
void ON_RESOURCES_LOADED ( )
{
TMPro_EventManager . RESOURCE_LOAD_EVENT . Remove ( ON_RESOURCES_LOADED ) ;
if ( this = = null )
return ;
2022-01-12 10:39:15 +03:00
m_isWaitingOnResourceLoad = false ;
2022-01-12 10:06:03 +03:00
Awake ( ) ;
OnEnable ( ) ;
}
// Event received when custom material editor properties are changed.
void ON_MATERIAL_PROPERTY_CHANGED ( bool isChanged , Material mat )
{
//Debug.Log("ON_MATERIAL_PROPERTY_CHANGED event received. Targeted Material is: " + mat.name + " m_sharedMaterial: " + m_sharedMaterial.name + " m_renderer.sharedMaterial: " + m_renderer.sharedMaterial);
if ( m_renderer . sharedMaterial = = null )
{
if ( m_fontAsset ! = null )
{
m_renderer . sharedMaterial = m_fontAsset . material ;
Debug . LogWarning ( "No Material was assigned to " + name + ". " + m_fontAsset . material . name + " was assigned." , this ) ;
}
else
Debug . LogWarning ( "No Font Asset assigned to " + name + ". Please assign a Font Asset." , this ) ;
}
// if (m_fontAsset.atlasTexture != null && m_fontAsset.atlasTexture.GetInstanceID() != m_renderer.sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
// {
// m_renderer.sharedMaterial = m_sharedMaterial;
// //m_renderer.sharedMaterial = m_fontAsset.material;
// 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);
// }
if ( m_renderer . sharedMaterial ! = m_sharedMaterial ) // || m_renderer.sharedMaterials.Contains(mat))
{
//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);
m_sharedMaterial = m_renderer . sharedMaterial ;
}
m_padding = GetPaddingForMaterial ( ) ;
//m_sharedMaterialHashCode = TMP_TextUtilities.GetSimpleHashCode(m_sharedMaterial.name);
UpdateMask ( ) ;
UpdateEnvMapMatrix ( ) ;
m_havePropertiesChanged = true ;
SetVerticesDirty ( ) ;
}
// Event received when font asset properties are changed in Font Inspector
void ON_FONT_PROPERTY_CHANGED ( bool isChanged , Object fontAsset )
{
//Debug.Log("ON_FONT_PROPERTY_CHANGED event received. Target is [" + font.name + "]");
if ( MaterialReference . Contains ( m_materialReferences , ( TMP_FontAsset ) fontAsset ) )
{
//Debug.Log("ON_FONT_PROPERTY_CHANGED event received.");
m_havePropertiesChanged = true ;
UpdateMeshPadding ( ) ;
SetMaterialDirty ( ) ;
SetVerticesDirty ( ) ;
}
}
// Event received when UNDO / REDO Event alters the properties of the object.
void ON_TEXTMESHPRO_PROPERTY_CHANGED ( bool isChanged , Object textComponent )
{
if ( textComponent = = this )
{
//Debug.Log("Undo / Redo Event Received by Object ID:" + GetInstanceID());
m_havePropertiesChanged = true ;
m_padding = GetPaddingForMaterial ( ) ;
ComputeMarginSize ( ) ; // Verify this change
SetVerticesDirty ( ) ;
}
}
// Event to Track Material Changed resulting from Drag-n-drop.
void ON_DRAG_AND_DROP_MATERIAL ( GameObject obj , Material currentMaterial , Material newMaterial )
{
//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());
// Check if event applies to this current object
#if UNITY_2018_2_OR_NEWER
if ( obj = = gameObject | | UnityEditor . PrefabUtility . GetCorrespondingObjectFromSource ( gameObject ) = = obj )
#else
if ( obj = = gameObject | | UnityEditor . PrefabUtility . GetPrefabParent ( gameObject ) = = obj )
#endif
{
UnityEditor . Undo . RecordObject ( this , "Material Assignment" ) ;
UnityEditor . Undo . RecordObject ( m_renderer , "Material Assignment" ) ;
m_sharedMaterial = newMaterial ;
m_padding = GetPaddingForMaterial ( ) ;
m_havePropertiesChanged = true ;
SetVerticesDirty ( ) ;
SetMaterialDirty ( ) ;
}
}
// Event received when Text Styles are changed.
void ON_TEXT_STYLE_CHANGED ( bool isChanged )
{
m_havePropertiesChanged = true ;
SetVerticesDirty ( ) ;
}
/// <summary>
/// Event received when a Color Gradient Preset is modified.
/// </summary>
/// <param name="textObject"></param>
void ON_COLOR_GRADIENT_CHANGED ( Object gradient )
{
m_havePropertiesChanged = true ;
SetVerticesDirty ( ) ;
}
/// <summary>
/// Event received when the TMP Settings are changed.
/// </summary>
void ON_TMP_SETTINGS_CHANGED ( )
{
m_defaultSpriteAsset = null ;
m_havePropertiesChanged = true ;
SetAllDirty ( ) ;
}
#endif
// Function which loads either the default font or a newly assigned font asset. This function also assigned the appropriate material to the renderer.
protected override void LoadFontAsset ( )
{
//Debug.Log("TextMeshPro LoadFontAsset() has been called."); // Current Font Asset is " + (font != null ? font.name: "Null") );
ShaderUtilities . GetShaderPropertyIDs ( ) ; // Initialize & Get shader property IDs.
if ( m_fontAsset = = null )
{
if ( TMP_Settings . defaultFontAsset ! = null )
m_fontAsset = TMP_Settings . defaultFontAsset ;
else
m_fontAsset = Resources . Load < TMP_FontAsset > ( "Fonts & Materials/LiberationSans SDF" ) ;
if ( m_fontAsset = = null )
{
Debug . LogWarning ( "The LiberationSans SDF Font Asset was not found. There is no Font Asset assigned to " + gameObject . name + "." , this ) ;
return ;
}
if ( m_fontAsset . characterLookupTable = = null )
{
Debug . Log ( "Dictionary is Null!" ) ;
}
m_sharedMaterial = m_fontAsset . material ;
m_sharedMaterial . SetFloat ( "_CullMode" , 0 ) ;
m_sharedMaterial . SetFloat ( ShaderUtilities . ShaderTag_ZTestMode , 4 ) ;
m_renderer . receiveShadows = false ;
m_renderer . shadowCastingMode = UnityEngine . Rendering . ShadowCastingMode . Off ;
}
else
{
if ( m_fontAsset . characterLookupTable = = null )
m_fontAsset . ReadFontAssetDefinition ( ) ;
// If font atlas texture doesn't match the assigned material font atlas, switch back to default material specified in the Font Asset.
if ( m_sharedMaterial = = null | | m_sharedMaterial . GetTexture ( ShaderUtilities . ID_MainTex ) = = null | | m_fontAsset . atlasTexture . GetInstanceID ( ) ! = m_sharedMaterial . GetTexture ( ShaderUtilities . ID_MainTex ) . GetInstanceID ( ) )
{
if ( m_fontAsset . material = = null )
Debug . LogWarning ( "The Font Atlas Texture of the Font Asset " + m_fontAsset . name + " assigned to " + gameObject . name + " is missing." , this ) ;
else
m_sharedMaterial = m_fontAsset . material ;
}
m_sharedMaterial . SetFloat ( ShaderUtilities . ShaderTag_ZTestMode , 4 ) ;
// Check if we are using the SDF Surface Shader
if ( m_sharedMaterial . passCount = = 1 )
{
m_renderer . receiveShadows = false ;
m_renderer . shadowCastingMode = UnityEngine . Rendering . ShadowCastingMode . Off ;
}
}
m_padding = GetPaddingForMaterial ( ) ;
m_isMaskingEnabled = ShaderUtilities . IsMaskingEnabled ( m_sharedMaterial ) ;
// Find and cache Underline & Ellipsis characters.
GetSpecialCharacters ( m_fontAsset ) ;
SetMaterialDirty ( ) ;
}
void UpdateEnvMapMatrix ( )
{
if ( ! m_sharedMaterial . HasProperty ( ShaderUtilities . ID_EnvMap ) | | m_sharedMaterial . GetTexture ( ShaderUtilities . ID_EnvMap ) = = null )
return ;
//Debug.Log("Updating Env Matrix...");
Vector3 rotation = m_sharedMaterial . GetVector ( ShaderUtilities . ID_EnvMatrixRotation ) ;
m_EnvMapMatrix = Matrix4x4 . TRS ( Vector3 . zero , Quaternion . Euler ( rotation ) , Vector3 . one ) ;
m_sharedMaterial . SetMatrix ( ShaderUtilities . ID_EnvMatrix , m_EnvMapMatrix ) ;
}
/ /
void SetMask ( MaskingTypes maskType )
{
switch ( maskType )
{
case MaskingTypes . MaskOff :
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_SOFT ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_HARD ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_TEX ) ;
break ;
case MaskingTypes . MaskSoft :
m_sharedMaterial . EnableKeyword ( ShaderUtilities . Keyword_MASK_SOFT ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_HARD ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_TEX ) ;
break ;
case MaskingTypes . MaskHard :
m_sharedMaterial . EnableKeyword ( ShaderUtilities . Keyword_MASK_HARD ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_SOFT ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_TEX ) ;
break ;
//case MaskingTypes.MaskTex:
// m_sharedMaterial.EnableKeyword(ShaderUtilities.Keyword_MASK_TEX);
// m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_HARD);
// m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_SOFT);
// break;
}
}
// Method used to set the masking coordinates
void SetMaskCoordinates ( Vector4 coords )
{
m_sharedMaterial . SetVector ( ShaderUtilities . ID_ClipRect , coords ) ;
}
// Method used to set the masking coordinates
void SetMaskCoordinates ( Vector4 coords , float softX , float softY )
{
m_sharedMaterial . SetVector ( ShaderUtilities . ID_ClipRect , coords ) ;
m_sharedMaterial . SetFloat ( ShaderUtilities . ID_MaskSoftnessX , softX ) ;
m_sharedMaterial . SetFloat ( ShaderUtilities . ID_MaskSoftnessY , softY ) ;
}
// Enable Masking in the Shader
void EnableMasking ( )
{
if ( m_sharedMaterial . HasProperty ( ShaderUtilities . ID_ClipRect ) )
{
m_sharedMaterial . EnableKeyword ( ShaderUtilities . Keyword_MASK_SOFT ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_HARD ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_TEX ) ;
m_isMaskingEnabled = true ;
UpdateMask ( ) ;
}
}
// Enable Masking in the Shader
void DisableMasking ( )
{
if ( m_sharedMaterial . HasProperty ( ShaderUtilities . ID_ClipRect ) )
{
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_SOFT ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_HARD ) ;
m_sharedMaterial . DisableKeyword ( ShaderUtilities . Keyword_MASK_TEX ) ;
m_isMaskingEnabled = false ;
UpdateMask ( ) ;
}
}
void UpdateMask ( )
{
//Debug.Log("UpdateMask() called.");
if ( ! m_isMaskingEnabled )
{
// Release Masking Material
// Re-assign Base Material
return ;
}
if ( m_isMaskingEnabled & & m_fontMaterial = = null )
{
CreateMaterialInstance ( ) ;
}
/ *
if ( ! m_isMaskingEnabled )
{
//Debug.Log("Masking is not enabled.");
if ( m_maskingPropertyBlock ! = null )
{
m_renderer . SetPropertyBlock ( null ) ;
//havePropertiesChanged = true;
}
return ;
}
//else
// Debug.Log("Updating Masking...");
* /
// Compute Masking Coordinates & Softness
//float softnessX = Mathf.Min(Mathf.Min(m_textContainer.margins.x, m_textContainer.margins.z), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX));
//float softnessY = Mathf.Min(Mathf.Min(m_textContainer.margins.y, m_textContainer.margins.w), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessY));
//softnessX = softnessX > 0 ? softnessX : 0;
//softnessY = softnessY > 0 ? softnessY : 0;
//float width = (m_textContainer.width - Mathf.Max(m_textContainer.margins.x, 0) - Mathf.Max(m_textContainer.margins.z, 0)) / 2 + softnessX;
//float height = (m_textContainer.height - Mathf.Max(m_textContainer.margins.y, 0) - Mathf.Max(m_textContainer.margins.w, 0)) / 2 + softnessY;
//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);
//Vector4 mask = new Vector4(center.x, center.y, width, height);
//m_fontMaterial.SetVector(ShaderUtilities.ID_ClipRect, mask);
//m_fontMaterial.SetFloat(ShaderUtilities.ID_MaskSoftnessX, softnessX);
//m_fontMaterial.SetFloat(ShaderUtilities.ID_MaskSoftnessY, softnessY);
/ *
if ( m_maskingPropertyBlock = = null )
{
m_maskingPropertyBlock = new MaterialPropertyBlock ( ) ;
//m_maskingPropertyBlock.AddFloat(ShaderUtilities.ID_VertexOffsetX, m_sharedMaterial.GetFloat(ShaderUtilities.ID_VertexOffsetX));
//m_maskingPropertyBlock.AddFloat(ShaderUtilities.ID_VertexOffsetY, m_sharedMaterial.GetFloat(ShaderUtilities.ID_VertexOffsetY));
//Debug.Log("Creating new MaterialPropertyBlock.");
}
//Debug.Log("Updating Material Property Block.");
//m_maskingPropertyBlock.Clear();
m_maskingPropertyBlock . AddFloat ( ShaderUtilities . ID_MaskID , m_renderer . GetInstanceID ( ) ) ;
m_maskingPropertyBlock . AddVector ( ShaderUtilities . ID_MaskCoord , mask ) ;
m_maskingPropertyBlock . AddFloat ( ShaderUtilities . ID_MaskSoftnessX , softnessX ) ;
m_maskingPropertyBlock . AddFloat ( ShaderUtilities . ID_MaskSoftnessY , softnessY ) ;
m_renderer . SetPropertyBlock ( m_maskingPropertyBlock ) ;
* /
}
// Function called internally when a new material is assigned via the fontMaterial property.
protected override Material GetMaterial ( Material mat )
{
// Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
// This can occur when the Duplicate Material Context menu is used on an inactive object.
//if (m_renderer == null)
// m_renderer = GetComponent<Renderer>();
// Create Instance Material only if the new material is not the same instance previously used.
if ( m_fontMaterial = = null | | m_fontMaterial . GetInstanceID ( ) ! = mat . GetInstanceID ( ) )
m_fontMaterial = CreateMaterialInstance ( mat ) ;
m_sharedMaterial = m_fontMaterial ;
m_padding = GetPaddingForMaterial ( ) ;
SetVerticesDirty ( ) ;
SetMaterialDirty ( ) ;
return m_sharedMaterial ;
}
/// <summary>
/// Method returning instances of the materials used by the text object.
/// </summary>
/// <returns></returns>
protected override Material [ ] GetMaterials ( Material [ ] mats )
{
int materialCount = m_textInfo . materialCount ;
if ( m_fontMaterials = = null )
m_fontMaterials = new Material [ materialCount ] ;
else if ( m_fontMaterials . Length ! = materialCount )
TMP_TextInfo . Resize ( ref m_fontMaterials , materialCount , false ) ;
// Get instances of the materials
for ( int i = 0 ; i < materialCount ; i + + )
{
if ( i = = 0 )
m_fontMaterials [ i ] = fontMaterial ;
else
m_fontMaterials [ i ] = m_subTextObjects [ i ] . material ;
}
m_fontSharedMaterials = m_fontMaterials ;
return m_fontMaterials ;
}
// Function called internally when a new shared material is assigned via the fontSharedMaterial property.
protected override void SetSharedMaterial ( Material mat )
{
// Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
// This can occur when the Duplicate Material Context menu is used on an inactive object.
//if (m_renderer == null)
// m_renderer = GetComponent<Renderer>();
m_sharedMaterial = mat ;
m_padding = GetPaddingForMaterial ( ) ;
SetMaterialDirty ( ) ;
}
/// <summary>
/// Method returning an array containing the materials used by the text object.
/// </summary>
/// <returns></returns>
protected override Material [ ] GetSharedMaterials ( )
{
int materialCount = m_textInfo . materialCount ;
if ( m_fontSharedMaterials = = null )
m_fontSharedMaterials = new Material [ materialCount ] ;
else if ( m_fontSharedMaterials . Length ! = materialCount )
TMP_TextInfo . Resize ( ref m_fontSharedMaterials , materialCount , false ) ;
for ( int i = 0 ; i < materialCount ; i + + )
{
if ( i = = 0 )
m_fontSharedMaterials [ i ] = m_sharedMaterial ;
else
m_fontSharedMaterials [ i ] = m_subTextObjects [ i ] . sharedMaterial ;
}
return m_fontSharedMaterials ;
}
/// <summary>
/// Method used to assign new materials to the text and sub text objects.
/// </summary>
protected override void SetSharedMaterials ( Material [ ] materials )
{
int materialCount = m_textInfo . materialCount ;
// Check allocation of the fontSharedMaterials array.
if ( m_fontSharedMaterials = = null )
m_fontSharedMaterials = new Material [ materialCount ] ;
else if ( m_fontSharedMaterials . Length ! = materialCount )
TMP_TextInfo . Resize ( ref m_fontSharedMaterials , materialCount , false ) ;
// Only assign as many materials as the text object contains.
for ( int i = 0 ; i < materialCount ; i + + )
{
Texture mat_MainTex = materials [ i ] . GetTexture ( ShaderUtilities . ID_MainTex ) ;
if ( i = = 0 )
{
// Only assign new material if the font atlas textures match.
if ( mat_MainTex = = null | | mat_MainTex . GetInstanceID ( ) ! = m_sharedMaterial . GetTexture ( ShaderUtilities . ID_MainTex ) . GetInstanceID ( ) )
continue ;
m_sharedMaterial = m_fontSharedMaterials [ i ] = materials [ i ] ;
m_padding = GetPaddingForMaterial ( m_sharedMaterial ) ;
}
else
{
// Only assign new material if the font atlas textures match.
if ( mat_MainTex = = null | | mat_MainTex . GetInstanceID ( ) ! = m_subTextObjects [ i ] . sharedMaterial . GetTexture ( ShaderUtilities . ID_MainTex ) . GetInstanceID ( ) )
continue ;
// Only assign a new material if none were specified in the text input.
if ( m_subTextObjects [ i ] . isDefaultMaterial )
m_subTextObjects [ i ] . sharedMaterial = m_fontSharedMaterials [ i ] = materials [ i ] ;
}
}
}
// This function will create an instance of the Font Material.
protected override void SetOutlineThickness ( float thickness )
{
thickness = Mathf . Clamp01 ( thickness ) ;
m_renderer . material . SetFloat ( ShaderUtilities . ID_OutlineWidth , thickness ) ;
if ( m_fontMaterial = = null )
m_fontMaterial = m_renderer . material ;
m_fontMaterial = m_renderer . material ;
m_sharedMaterial = m_fontMaterial ;
m_padding = GetPaddingForMaterial ( ) ;
}
// This function will create an instance of the Font Material.
protected override void SetFaceColor ( Color32 color )
{
m_renderer . material . SetColor ( ShaderUtilities . ID_FaceColor , color ) ;
if ( m_fontMaterial = = null )
m_fontMaterial = m_renderer . material ;
m_sharedMaterial = m_fontMaterial ;
}
// This function will create an instance of the Font Material.
protected override void SetOutlineColor ( Color32 color )
{
m_renderer . material . SetColor ( ShaderUtilities . ID_OutlineColor , color ) ;
if ( m_fontMaterial = = null )
m_fontMaterial = m_renderer . material ;
//Debug.Log("Material ID:" + m_fontMaterial.GetInstanceID());
m_sharedMaterial = m_fontMaterial ;
}
// Function used to create an instance of the material
void CreateMaterialInstance ( )
{
Material mat = new Material ( m_sharedMaterial ) ;
mat . shaderKeywords = m_sharedMaterial . shaderKeywords ;
//mat.hideFlags = HideFlags.DontSave;
mat . name + = " Instance" ;
m_fontMaterial = mat ;
}
// Sets the Render Queue and Ztest mode
protected override void SetShaderDepth ( )
{
if ( m_isOverlay )
{
// Changing these properties results in an instance of the material
m_sharedMaterial . SetFloat ( ShaderUtilities . ShaderTag_ZTestMode , 0 ) ;
//m_renderer.material.SetFloat("_ZTestMode", 8);
m_renderer . material . renderQueue = 4000 ;
m_sharedMaterial = m_renderer . material ;
//Debug.Log("Text set to Overlay mode.");
}
else
{
// Should this use an instanced material?
m_sharedMaterial . SetFloat ( ShaderUtilities . ShaderTag_ZTestMode , 4 ) ;
m_renderer . material . renderQueue = - 1 ;
m_sharedMaterial = m_renderer . material ;
//Debug.Log("Text set to Normal mode.");
}
}
// Sets the Culling mode of the material
protected override void SetCulling ( )
{
if ( m_isCullingEnabled )
{
m_renderer . material . SetFloat ( "_CullMode" , 2 ) ;
for ( int i = 1 ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
{
Renderer renderer = m_subTextObjects [ i ] . renderer ;
if ( renderer ! = null )
{
renderer . material . SetFloat ( ShaderUtilities . ShaderTag_CullMode , 2 ) ;
}
}
}
else
{
m_renderer . material . SetFloat ( "_CullMode" , 0 ) ;
for ( int i = 1 ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
{
Renderer renderer = m_subTextObjects [ i ] . renderer ;
if ( renderer ! = null )
{
renderer . material . SetFloat ( ShaderUtilities . ShaderTag_CullMode , 0 ) ;
}
}
}
}
// Set Perspective Correction Mode based on whether Camera is Orthographic or Perspective
void SetPerspectiveCorrection ( )
{
if ( m_isOrthographic )
m_sharedMaterial . SetFloat ( ShaderUtilities . ID_PerspectiveFilter , 0.0f ) ;
else
m_sharedMaterial . SetFloat ( ShaderUtilities . ID_PerspectiveFilter , 0.875f ) ;
}
// 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.
2022-01-12 10:39:15 +03:00
internal override int SetArraySizes ( UnicodeChar [ ] unicodeChars )
2022-01-12 10:06:03 +03:00
{
2022-01-12 10:39:15 +03:00
k_SetArraySizesMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
int spriteCount = 0 ;
m_totalCharacterCount = 0 ;
m_isUsingBold = false ;
m_isParsingText = false ;
tag_NoParsing = false ;
m_FontStyleInternal = m_fontStyle ;
m_fontStyleStack . Clear ( ) ;
m_FontWeightInternal = ( m_FontStyleInternal & FontStyles . Bold ) = = FontStyles . Bold ? FontWeight . Bold : m_fontWeight ;
m_FontWeightStack . SetDefault ( m_FontWeightInternal ) ;
m_currentFontAsset = m_fontAsset ;
m_currentMaterial = m_sharedMaterial ;
m_currentMaterialIndex = 0 ;
m_materialReferenceStack . SetDefault ( new MaterialReference ( m_currentMaterialIndex , m_currentFontAsset , null , m_currentMaterial , m_padding ) ) ;
m_materialReferenceIndexLookup . Clear ( ) ;
2022-01-12 10:39:15 +03:00
MaterialReference . AddMaterialReference ( m_currentMaterial , m_currentFontAsset , ref m_materialReferences , m_materialReferenceIndexLookup ) ;
2022-01-12 10:06:03 +03:00
// Set allocations for the text object's TextInfo
if ( m_textInfo = = null )
2022-01-12 10:39:15 +03:00
m_textInfo = new TMP_TextInfo ( m_InternalTextProcessingArraySize ) ;
else if ( m_textInfo . characterInfo . Length < m_InternalTextProcessingArraySize )
TMP_TextInfo . Resize ( ref m_textInfo . characterInfo , m_InternalTextProcessingArraySize , false ) ;
2022-01-12 10:06:03 +03:00
m_textElementType = TMP_TextElementType . Character ;
// Handling for Underline special character
#region Setup Underline Special Character
/ *
GetUnderlineSpecialCharacter ( m_currentFontAsset ) ;
if ( m_Underline . character ! = null )
{
if ( m_Underline . fontAsset . GetInstanceID ( ) ! = m_currentFontAsset . GetInstanceID ( ) )
{
if ( TMP_Settings . matchMaterialPreset & & m_currentMaterial . GetInstanceID ( ) ! = m_Underline . fontAsset . material . GetInstanceID ( ) )
m_Underline . material = TMP_MaterialManager . GetFallbackMaterial ( m_currentMaterial , m_Underline . fontAsset . material ) ;
else
m_Underline . material = m_Underline . fontAsset . material ;
m_Underline . materialIndex = MaterialReference . AddMaterialReference ( m_Underline . material , m_Underline . fontAsset , m_materialReferences , m_materialReferenceIndexLookup ) ;
m_materialReferences [ m_Underline . materialIndex ] . referenceCount = 0 ;
}
}
* /
#endregion
// Handling for Ellipsis special character
#region Setup Ellipsis Special Character
if ( m_overflowMode = = TextOverflowModes . Ellipsis )
{
GetEllipsisSpecialCharacter ( m_currentFontAsset ) ;
if ( m_Ellipsis . character ! = null )
{
if ( m_Ellipsis . fontAsset . GetInstanceID ( ) ! = m_currentFontAsset . GetInstanceID ( ) )
{
if ( TMP_Settings . matchMaterialPreset & & m_currentMaterial . GetInstanceID ( ) ! = m_Ellipsis . fontAsset . material . GetInstanceID ( ) )
m_Ellipsis . material = TMP_MaterialManager . GetFallbackMaterial ( m_currentMaterial , m_Ellipsis . fontAsset . material ) ;
else
m_Ellipsis . material = m_Ellipsis . fontAsset . material ;
2022-01-12 10:39:15 +03:00
m_Ellipsis . materialIndex = MaterialReference . AddMaterialReference ( m_Ellipsis . material , m_Ellipsis . fontAsset , ref m_materialReferences , m_materialReferenceIndexLookup ) ;
2022-01-12 10:06:03 +03:00
m_materialReferences [ m_Ellipsis . materialIndex ] . referenceCount = 0 ;
}
}
else
{
m_overflowMode = TextOverflowModes . Truncate ;
if ( ! TMP_Settings . warningsDisabled )
Debug . LogWarning ( "The character used for Ellipsis is not available in font asset [" + m_currentFontAsset . name + "] or any potential fallbacks. Switching Text Overflow mode to Truncate." , this ) ;
}
}
#endregion
// Clear Linked Text object if we have one.
2022-01-12 10:39:15 +03:00
if ( m_overflowMode = = TextOverflowModes . Linked & & m_linkedTextComponent ! = null & & ! m_isCalculatingPreferredValues )
2022-01-12 10:06:03 +03:00
m_linkedTextComponent . text = string . Empty ;
// Parsing XML tags in the text
for ( int i = 0 ; i < unicodeChars . Length & & unicodeChars [ i ] . unicode ! = 0 ; i + + )
{
//Make sure the characterInfo array can hold the next text element.
if ( m_textInfo . characterInfo = = null | | m_totalCharacterCount > = m_textInfo . characterInfo . Length )
TMP_TextInfo . Resize ( ref m_textInfo . characterInfo , m_totalCharacterCount + 1 , true ) ;
int unicode = unicodeChars [ i ] . unicode ;
// PARSE XML TAGS
#region PARSE XML TAGS
if ( m_isRichText & & unicode = = 60 ) // if Char '<'
{
int prev_MaterialIndex = m_currentMaterialIndex ;
int endTagIndex ;
// Check if Tag is Valid
if ( ValidateHtmlTag ( unicodeChars , i + 1 , out endTagIndex ) )
{
int tagStartIndex = unicodeChars [ i ] . stringIndex ;
i = endTagIndex ;
if ( ( m_FontStyleInternal & FontStyles . Bold ) = = FontStyles . Bold )
m_isUsingBold = true ;
if ( m_textElementType = = TMP_TextElementType . Sprite )
{
m_materialReferences [ m_currentMaterialIndex ] . referenceCount + = 1 ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . character = ( char ) ( 57344 + m_spriteIndex ) ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . spriteIndex = m_spriteIndex ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . fontAsset = m_currentFontAsset ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . spriteAsset = m_currentSpriteAsset ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . materialReferenceIndex = m_currentMaterialIndex ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . textElement = m_currentSpriteAsset . spriteCharacterTable [ m_spriteIndex ] ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . elementType = m_textElementType ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . index = tagStartIndex ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . stringLength = unicodeChars [ i ] . stringIndex - tagStartIndex + 1 ;
// Restore element type and material index to previous values.
m_textElementType = TMP_TextElementType . Character ;
m_currentMaterialIndex = prev_MaterialIndex ;
spriteCount + = 1 ;
m_totalCharacterCount + = 1 ;
}
continue ;
}
}
#endregion
2022-01-12 10:39:15 +03:00
bool isUsingAlternativeTypeface ;
2022-01-12 10:06:03 +03:00
bool isUsingFallbackOrAlternativeTypeface = false ;
TMP_FontAsset prev_fontAsset = m_currentFontAsset ;
Material prev_material = m_currentMaterial ;
int prev_materialIndex = m_currentMaterialIndex ;
// Handle Font Styles like LowerCase, UpperCase and SmallCaps.
#region Handling of LowerCase , UpperCase and SmallCaps Font Styles
if ( m_textElementType = = TMP_TextElementType . Character )
{
if ( ( m_FontStyleInternal & FontStyles . UpperCase ) = = FontStyles . UpperCase )
{
// If this character is lowercase, switch to uppercase.
if ( char . IsLower ( ( char ) unicode ) )
unicode = char . ToUpper ( ( char ) unicode ) ;
}
else if ( ( m_FontStyleInternal & FontStyles . LowerCase ) = = FontStyles . LowerCase )
{
// If this character is uppercase, switch to lowercase.
if ( char . IsUpper ( ( char ) unicode ) )
unicode = char . ToLower ( ( char ) unicode ) ;
}
else if ( ( m_FontStyleInternal & FontStyles . SmallCaps ) = = FontStyles . SmallCaps )
{
// Only convert lowercase characters to uppercase.
if ( char . IsLower ( ( char ) unicode ) )
unicode = char . ToUpper ( ( char ) unicode ) ;
}
}
#endregion
// Lookup the Glyph data for each character and cache it.
#region LOOKUP GLYPH
TMP_TextElement character = GetTextElement ( ( uint ) unicode , m_currentFontAsset , m_FontStyleInternal , m_FontWeightInternal , out isUsingAlternativeTypeface ) ;
// Check if Lowercase or Uppercase variant of the character is available.
/ * Not sure this is necessary anyone as it is very unlikely with recursive search through fallback fonts .
if ( glyph = = null )
{
if ( char . IsLower ( ( char ) c ) )
{
if ( m_currentFontAsset . characterDictionary . TryGetValue ( char . ToUpper ( ( char ) c ) , out glyph ) )
c = chars [ i ] = char . ToUpper ( ( char ) c ) ;
}
else if ( char . IsUpper ( ( char ) c ) )
{
if ( m_currentFontAsset . characterDictionary . TryGetValue ( char . ToLower ( ( char ) c ) , out glyph ) )
c = chars [ i ] = char . ToLower ( ( char ) c ) ;
}
} * /
// Special handling for missing character.
// Replace missing glyph by the Square (9633) glyph or possibly the Space (32) glyph.
if ( character = = null )
{
// Save the original unicode character
int srcGlyph = unicode ;
// Try replacing the missing glyph character by TMP Settings Missing Glyph or Square (9633) character.
unicode = unicodeChars [ i ] . unicode = TMP_Settings . missingGlyphCharacter = = 0 ? 9633 : TMP_Settings . missingGlyphCharacter ;
// Check for the missing glyph character in the currently assigned font asset and its fallbacks
character = TMP_FontAssetUtilities . GetCharacterFromFontAsset ( ( uint ) unicode , m_currentFontAsset , true , m_FontStyleInternal , m_FontWeightInternal , out isUsingAlternativeTypeface ) ;
if ( character = = null )
{
// Search for the missing glyph character in the TMP Settings Fallback list.
if ( TMP_Settings . fallbackFontAssets ! = null & & TMP_Settings . fallbackFontAssets . Count > 0 )
character = TMP_FontAssetUtilities . GetCharacterFromFontAssets ( ( uint ) unicode , m_currentFontAsset , TMP_Settings . fallbackFontAssets , true , m_FontStyleInternal , m_FontWeightInternal , out isUsingAlternativeTypeface ) ;
}
if ( character = = null )
{
// Search for the missing glyph in the TMP Settings Default Font Asset.
if ( TMP_Settings . defaultFontAsset ! = null )
character = TMP_FontAssetUtilities . GetCharacterFromFontAsset ( ( uint ) unicode , TMP_Settings . defaultFontAsset , true , m_FontStyleInternal , m_FontWeightInternal , out isUsingAlternativeTypeface ) ;
}
if ( character = = null )
{
// Use Space (32) Glyph from the currently assigned font asset.
unicode = unicodeChars [ i ] . unicode = 32 ;
character = TMP_FontAssetUtilities . GetCharacterFromFontAsset ( ( uint ) unicode , m_currentFontAsset , true , m_FontStyleInternal , m_FontWeightInternal , out isUsingAlternativeTypeface ) ;
}
if ( character = = null )
{
// Use End of Text (0x03) Glyph from the currently assigned font asset.
unicode = unicodeChars [ i ] . unicode = 0x03 ;
character = TMP_FontAssetUtilities . GetCharacterFromFontAsset ( ( uint ) unicode , m_currentFontAsset , true , m_FontStyleInternal , m_FontWeightInternal , out isUsingAlternativeTypeface ) ;
}
if ( ! TMP_Settings . warningsDisabled )
{
string formattedWarning = srcGlyph > 0xFFFF
? string . Format ( "The character with Unicode value \\U{0:X8} was not found in the [{1}] font asset or any potential fallbacks. It was replaced by Unicode character \\u{2:X4} in text object [{3}]." , srcGlyph , m_fontAsset . name , character . unicode , this . name )
: string . Format ( "The character with Unicode value \\u{0:X4} was not found in the [{1}] font asset or any potential fallbacks. It was replaced by Unicode character \\u{2:X4} in text object [{3}]." , srcGlyph , m_fontAsset . name , character . unicode , this . name ) ;
Debug . LogWarning ( formattedWarning , this ) ;
}
}
if ( character . elementType = = TextElementType . Character )
{
if ( character . textAsset . instanceID ! = m_currentFontAsset . instanceID )
{
isUsingFallbackOrAlternativeTypeface = true ;
m_currentFontAsset = character . textAsset as TMP_FontAsset ;
}
}
#endregion
// Save text element data
m_textInfo . characterInfo [ m_totalCharacterCount ] . elementType = TMP_TextElementType . Character ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . textElement = character ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . isUsingAlternateTypeface = isUsingAlternativeTypeface ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . character = ( char ) unicode ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . index = unicodeChars [ i ] . stringIndex ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . stringLength = unicodeChars [ i ] . length ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . fontAsset = m_currentFontAsset ;
// Special handling if the character is a sprite.
if ( character . elementType = = TextElementType . Sprite )
{
TMP_SpriteAsset spriteAssetRef = character . textAsset as TMP_SpriteAsset ;
2022-01-12 10:39:15 +03:00
m_currentMaterialIndex = MaterialReference . AddMaterialReference ( spriteAssetRef . material , spriteAssetRef , ref m_materialReferences , m_materialReferenceIndexLookup ) ;
2022-01-12 10:06:03 +03:00
m_materialReferences [ m_currentMaterialIndex ] . referenceCount + = 1 ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . elementType = TMP_TextElementType . Sprite ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . materialReferenceIndex = m_currentMaterialIndex ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . spriteAsset = spriteAssetRef ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . spriteIndex = ( int ) character . glyphIndex ;
// Restore element type and material index to previous values.
m_textElementType = TMP_TextElementType . Character ;
m_currentMaterialIndex = prev_materialIndex ;
spriteCount + = 1 ;
m_totalCharacterCount + = 1 ;
continue ;
}
if ( isUsingFallbackOrAlternativeTypeface & & m_currentFontAsset . instanceID ! = m_fontAsset . instanceID )
{
// Create Fallback material instance matching current material preset if necessary
if ( TMP_Settings . matchMaterialPreset )
m_currentMaterial = TMP_MaterialManager . GetFallbackMaterial ( m_currentMaterial , m_currentFontAsset . material ) ;
else
m_currentMaterial = m_currentFontAsset . material ;
2022-01-12 10:39:15 +03:00
m_currentMaterialIndex = MaterialReference . AddMaterialReference ( m_currentMaterial , m_currentFontAsset , ref m_materialReferences , m_materialReferenceIndexLookup ) ;
2022-01-12 10:06:03 +03:00
}
// Handle Multi Atlas Texture support
if ( character ! = null & & character . glyph . atlasIndex > 0 )
{
m_currentMaterial = TMP_MaterialManager . GetFallbackMaterial ( m_currentFontAsset , m_currentMaterial , character . glyph . atlasIndex ) ;
2022-01-12 10:39:15 +03:00
m_currentMaterialIndex = MaterialReference . AddMaterialReference ( m_currentMaterial , m_currentFontAsset , ref m_materialReferences , m_materialReferenceIndexLookup ) ;
2022-01-12 10:06:03 +03:00
isUsingFallbackOrAlternativeTypeface = true ;
}
if ( ! char . IsWhiteSpace ( ( char ) unicode ) & & unicode ! = 0x200B )
{
// Limit the mesh of the main text object to 65535 vertices and use sub objects for the overflow.
if ( m_materialReferences [ m_currentMaterialIndex ] . referenceCount < 16383 )
m_materialReferences [ m_currentMaterialIndex ] . referenceCount + = 1 ;
else
{
2022-01-12 10:39:15 +03:00
m_currentMaterialIndex = MaterialReference . AddMaterialReference ( new Material ( m_currentMaterial ) , m_currentFontAsset , ref m_materialReferences , m_materialReferenceIndexLookup ) ;
2022-01-12 10:06:03 +03:00
m_materialReferences [ m_currentMaterialIndex ] . referenceCount + = 1 ;
}
}
m_textInfo . characterInfo [ m_totalCharacterCount ] . material = m_currentMaterial ;
m_textInfo . characterInfo [ m_totalCharacterCount ] . materialReferenceIndex = m_currentMaterialIndex ;
m_materialReferences [ m_currentMaterialIndex ] . isFallbackMaterial = isUsingFallbackOrAlternativeTypeface ;
// Restore previous font asset and material if fallback font was used.
if ( isUsingFallbackOrAlternativeTypeface )
{
m_materialReferences [ m_currentMaterialIndex ] . fallbackMaterial = prev_material ;
m_currentFontAsset = prev_fontAsset ;
m_currentMaterial = prev_material ;
m_currentMaterialIndex = prev_materialIndex ;
}
m_totalCharacterCount + = 1 ;
}
// Early return if we are calculating the preferred values.
if ( m_isCalculatingPreferredValues )
{
m_isCalculatingPreferredValues = false ;
2022-01-12 10:39:15 +03:00
k_SetArraySizesMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return m_totalCharacterCount ;
}
// Save material and sprite count.
m_textInfo . spriteCount = spriteCount ;
int materialCount = m_textInfo . materialCount = m_materialReferenceIndexLookup . Count ;
// Check if we need to resize the MeshInfo array for handling different materials.
if ( materialCount > m_textInfo . meshInfo . Length )
TMP_TextInfo . Resize ( ref m_textInfo . meshInfo , materialCount , false ) ;
// Resize SubTextObject array if necessary
if ( materialCount > m_subTextObjects . Length )
TMP_TextInfo . Resize ( ref m_subTextObjects , Mathf . NextPowerOfTwo ( materialCount + 1 ) ) ;
// Resize CharacterInfo[] if allocations are excessive
2022-01-12 10:39:15 +03:00
if ( m_VertexBufferAutoSizeReduction & & m_textInfo . characterInfo . Length - m_totalCharacterCount > 256 )
2022-01-12 10:06:03 +03:00
TMP_TextInfo . Resize ( ref m_textInfo . characterInfo , Mathf . Max ( m_totalCharacterCount + 1 , 256 ) , true ) ;
// Iterate through the material references to set the mesh buffer allocations
for ( int i = 0 ; i < materialCount ; i + + )
{
// Add new sub text object for each material reference
if ( i > 0 )
{
if ( m_subTextObjects [ i ] = = null )
{
m_subTextObjects [ i ] = TMP_SubMesh . AddSubTextObject ( this , m_materialReferences [ i ] ) ;
// Not sure this is necessary
m_textInfo . meshInfo [ i ] . vertices = null ;
}
//else if (m_subTextObjects[i].gameObject.activeInHierarchy == false)
// m_subTextObjects[i].gameObject.SetActive(true);
// Check if the material has changed.
if ( m_subTextObjects [ i ] . sharedMaterial = = null | | m_subTextObjects [ i ] . sharedMaterial . GetInstanceID ( ) ! = m_materialReferences [ i ] . material . GetInstanceID ( ) )
{
m_subTextObjects [ i ] . sharedMaterial = m_materialReferences [ i ] . material ;
m_subTextObjects [ i ] . fontAsset = m_materialReferences [ i ] . fontAsset ;
m_subTextObjects [ i ] . spriteAsset = m_materialReferences [ i ] . spriteAsset ;
}
// Check if we need to use a Fallback Material
if ( m_materialReferences [ i ] . isFallbackMaterial )
{
m_subTextObjects [ i ] . fallbackMaterial = m_materialReferences [ i ] . material ;
m_subTextObjects [ i ] . fallbackSourceMaterial = m_materialReferences [ i ] . fallbackMaterial ;
}
}
int referenceCount = m_materialReferences [ i ] . referenceCount ;
// Check to make sure our buffers allocations can accommodate the required text elements.
2022-01-12 10:39:15 +03:00
if ( m_textInfo . meshInfo [ i ] . vertices = = null | | m_textInfo . meshInfo [ i ] . vertices . Length < referenceCount * 4 )
2022-01-12 10:06:03 +03:00
{
if ( m_textInfo . meshInfo [ i ] . vertices = = null )
{
if ( i = = 0 )
2022-01-12 10:39:15 +03:00
m_textInfo . meshInfo [ i ] = new TMP_MeshInfo ( m_mesh , referenceCount + 1 ) ;
2022-01-12 10:06:03 +03:00
else
2022-01-12 10:39:15 +03:00
m_textInfo . meshInfo [ i ] = new TMP_MeshInfo ( m_subTextObjects [ i ] . mesh , referenceCount + 1 ) ;
2022-01-12 10:06:03 +03:00
}
else
2022-01-12 10:39:15 +03:00
m_textInfo . meshInfo [ i ] . ResizeMeshInfo ( referenceCount > 1024 ? referenceCount + 256 : Mathf . NextPowerOfTwo ( referenceCount + 1 ) ) ;
2022-01-12 10:06:03 +03:00
}
2022-01-12 10:39:15 +03:00
else if ( m_VertexBufferAutoSizeReduction & & referenceCount > 0 & & m_textInfo . meshInfo [ i ] . vertices . Length / 4 - referenceCount > 256 )
2022-01-12 10:06:03 +03:00
{
// Resize vertex buffers if allocations are excessive.
//Debug.Log("Reducing the size of the vertex buffers.");
2022-01-12 10:39:15 +03:00
m_textInfo . meshInfo [ i ] . ResizeMeshInfo ( referenceCount > 1024 ? referenceCount + 256 : Mathf . NextPowerOfTwo ( referenceCount + 1 ) ) ;
2022-01-12 10:06:03 +03:00
}
// Assign material reference
m_textInfo . meshInfo [ i ] . material = m_materialReferences [ i ] . material ;
}
//TMP_MaterialManager.CleanupFallbackMaterials();
// Clean up unused SubMeshes
for ( int i = materialCount ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
{
if ( i < m_textInfo . meshInfo . Length )
m_textInfo . meshInfo [ i ] . ClearUnusedVertices ( 0 , true ) ;
//m_subTextObjects[i].gameObject.SetActive(false);
}
2022-01-12 10:39:15 +03:00
k_SetArraySizesMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return m_totalCharacterCount ;
}
// Added to sort handle the potential issue with OnWillRenderObject() not getting called when objects are not visible by camera.
//void OnBecameInvisible()
//{
// if (m_mesh != null)
// m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0));
//}
/// <summary>
/// Update the margin width and height
/// </summary>
public override void ComputeMarginSize ( )
{
if ( this . rectTransform ! = null )
{
//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);
Rect rect = m_rectTransform . rect ;
m_marginWidth = rect . width - m_margin . x - m_margin . z ;
m_marginHeight = rect . height - m_margin . y - m_margin . w ;
// Cache current RectTransform width and pivot referenced in OnRectTransformDimensionsChange() to get around potential rounding error in the reported width of the RectTransform.
m_PreviousRectTransformSize = rect . size ;
m_PreviousPivotPosition = m_rectTransform . pivot ;
// Update the corners of the RectTransform
m_RectTransformCorners = GetTextContainerLocalCorners ( ) ;
}
}
2022-01-12 10:39:15 +03:00
/// <summary>
///
/// </summary>
2022-01-12 10:06:03 +03:00
protected override void OnDidApplyAnimationProperties ( )
{
//Debug.Log("*** OnDidApplyAnimationProperties() ***");
m_havePropertiesChanged = true ;
isMaskUpdateRequired = true ;
SetVerticesDirty ( ) ;
}
protected override void OnTransformParentChanged ( )
{
//Debug.Log("*** OnTransformParentChanged() ***");
//ComputeMarginSize();
SetVerticesDirty ( ) ;
SetLayoutDirty ( ) ;
}
protected override void OnRectTransformDimensionsChange ( )
{
//Debug.Log("*** OnRectTransformDimensionsChange() ***");
// Ignore changes to RectTransform SizeDelta that are very small and typically the result of rounding errors when using RectTransform in Anchor Stretch mode.
if ( rectTransform ! = null & &
Mathf . Abs ( m_rectTransform . rect . width - m_PreviousRectTransformSize . x ) < 0.0001f & & Mathf . Abs ( m_rectTransform . rect . height - m_PreviousRectTransformSize . y ) < 0.0001f & &
Mathf . Abs ( m_rectTransform . pivot . x - m_PreviousPivotPosition . x ) < 0.0001f & & Mathf . Abs ( m_rectTransform . pivot . y - m_PreviousPivotPosition . y ) < 0.0001f )
{
return ;
}
ComputeMarginSize ( ) ;
SetVerticesDirty ( ) ;
SetLayoutDirty ( ) ;
}
/// <summary>
/// Function used as a replacement for LateUpdate to check if the transform or scale of the text object has changed.
/// </summary>
internal override void InternalUpdate ( )
{
// We need to update the SDF scale or possibly regenerate the text object if lossy scale has changed.
if ( m_havePropertiesChanged = = false )
{
float lossyScaleY = m_rectTransform . lossyScale . y ;
// Ignore very small lossy scale changes as their effect on SDF Scale would not be visually noticeable.
// Do not update SDF Scale if the text is null or empty
2022-01-12 10:39:15 +03:00
if ( Mathf . Abs ( lossyScaleY - m_previousLossyScaleY ) > 0.0001f & & m_TextProcessingArray [ 0 ] . unicode ! = 0 )
2022-01-12 10:06:03 +03:00
{
float scaleDelta = lossyScaleY / m_previousLossyScaleY ;
UpdateSDFScale ( scaleDelta ) ;
m_previousLossyScaleY = lossyScaleY ;
}
}
// Added to handle legacy animation mode.
if ( m_isUsingLegacyAnimationComponent )
{
//if (m_havePropertiesChanged)
m_havePropertiesChanged = true ;
OnPreRenderObject ( ) ;
}
}
/// <summary>
/// Function called when the text needs to be updated.
/// </summary>
void OnPreRenderObject ( )
{
//Debug.Log("*** OnPreRenderObject() called on object [" + this.name + "] ***");
2022-01-12 10:39:15 +03:00
// Make sure object is active.
if ( ! m_isAwake | | ( this . IsActive ( ) = = false & & m_ignoreActiveState = = false ) )
return ;
2022-01-12 10:06:03 +03:00
// Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen.
if ( m_fontAsset = = null )
{
Debug . LogWarning ( "Please assign a Font Asset to this " + transform . name + " gameobject." , this ) ;
return ;
}
if ( m_havePropertiesChanged | | m_isLayoutDirty )
{
//Debug.Log("Properties have changed!"); // Assigned Material is:" + m_sharedMaterial); // New Text is: " + m_text + ".");
if ( isMaskUpdateRequired )
{
UpdateMask ( ) ;
isMaskUpdateRequired = false ;
}
// Update mesh padding if necessary.
if ( checkPaddingRequired )
UpdateMeshPadding ( ) ;
2022-01-12 10:39:15 +03:00
// Reparse the text as input may have changed or been truncated.
ParseInputText ( ) ;
TMP_FontAsset . UpdateFontFeaturesForFontAssetsInQueue ( ) ;
2022-01-12 10:06:03 +03:00
// Reset Font min / max used with Auto-sizing
if ( m_enableAutoSizing )
m_fontSize = Mathf . Clamp ( m_fontSizeBase , m_fontSizeMin , m_fontSizeMax ) ;
m_maxFontSize = m_fontSizeMax ;
m_minFontSize = m_fontSizeMin ;
m_lineSpacingDelta = 0 ;
m_charWidthAdjDelta = 0 ;
m_isTextTruncated = false ;
m_havePropertiesChanged = false ;
m_isLayoutDirty = false ;
m_ignoreActiveState = false ;
// Reset Text Auto Size iteration tracking.
m_IsAutoSizePointSizeSet = false ;
m_AutoSizeIterationCount = 0 ;
2022-01-12 10:39:15 +03:00
// Make sure state of MeshRenderer is mirrored on potential sub text objects.
SetActiveSubTextObjectRenderers ( m_renderer . enabled ) ;
2022-01-12 10:06:03 +03:00
// The GenerateTextMesh function is potentially called repeatedly when text auto size is enabled.
// This is a revised implementation to remove the use of recursion which could potentially result in stack overflow issues.
while ( m_IsAutoSizePointSizeSet = = false )
{
GenerateTextMesh ( ) ;
m_AutoSizeIterationCount + = 1 ;
}
}
}
/// <summary>
/// This is the main function that is responsible for creating / displaying the text.
/// </summary>
2022-01-12 10:39:15 +03:00
protected virtual void GenerateTextMesh ( )
2022-01-12 10:06:03 +03:00
{
2022-01-12 10:39:15 +03:00
k_GenerateTextMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Early exit if no font asset was assigned. This should not be needed since LiberationSans SDF will be assigned by default.
if ( m_fontAsset = = null | | m_fontAsset . characterLookupTable = = null )
{
Debug . LogWarning ( "Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this . GetInstanceID ( ) ) ;
m_IsAutoSizePointSizeSet = true ;
2022-01-12 10:39:15 +03:00
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
// Clear TextInfo
if ( m_textInfo ! = null )
m_textInfo . Clear ( ) ;
// Early exit if we don't have any Text to generate.
2022-01-12 10:39:15 +03:00
if ( m_TextProcessingArray = = null | | m_TextProcessingArray . Length = = 0 | | m_TextProcessingArray [ 0 ] . unicode = = 0 )
2022-01-12 10:06:03 +03:00
{
// Clear mesh and upload changes to the mesh.
ClearMesh ( true ) ;
m_preferredWidth = 0 ;
m_preferredHeight = 0 ;
// Event indicating the text has been regenerated.
TMPro_EventManager . ON_TEXT_CHANGED ( this ) ;
m_IsAutoSizePointSizeSet = true ;
2022-01-12 10:39:15 +03:00
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
m_currentFontAsset = m_fontAsset ;
m_currentMaterial = m_sharedMaterial ;
m_currentMaterialIndex = 0 ;
m_materialReferenceStack . SetDefault ( new MaterialReference ( m_currentMaterialIndex , m_currentFontAsset , null , m_currentMaterial , m_padding ) ) ;
m_currentSpriteAsset = m_spriteAsset ;
// Stop all Sprite Animations
if ( m_spriteAnimator ! = null )
m_spriteAnimator . StopAllAnimations ( ) ;
// Total character count is computed when the text is parsed.
int totalCharacterCount = m_totalCharacterCount ;
// Calculate the scale of the font based on selected font size and sampling point size.
// baseScale is calculated using the font asset assigned to the text object.
2022-01-12 10:39:15 +03:00
float baseScale = ( m_fontSize / m_fontAsset . m_FaceInfo . pointSize * m_fontAsset . m_FaceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ) ;
2022-01-12 10:06:03 +03:00
float currentElementScale = baseScale ;
float currentEmScale = m_fontSize * 0.01f * ( m_isOrthographic ? 1 : 0.1f ) ;
m_fontScaleMultiplier = 1 ;
m_currentFontSize = m_fontSize ;
m_sizeStack . SetDefault ( m_currentFontSize ) ;
float fontSizeDelta = 0 ;
int charCode = 0 ; // Holds the character code of the currently being processed character.
m_FontStyleInternal = m_fontStyle ; // Set the default style.
m_FontWeightInternal = ( m_FontStyleInternal & FontStyles . Bold ) = = FontStyles . Bold ? FontWeight . Bold : m_fontWeight ;
m_FontWeightStack . SetDefault ( m_FontWeightInternal ) ;
m_fontStyleStack . Clear ( ) ;
m_lineJustification = m_HorizontalAlignment ; // m_textAlignment; // Sets the line justification mode to match editor alignment.
m_lineJustificationStack . SetDefault ( m_lineJustification ) ;
float padding = 0 ;
float style_padding = 0 ; // Extra padding required to accommodate Bold style.
float boldSpacingAdjustment = 0 ;
//float bold_xAdvance_multiplier = 1; // Used to increase spacing between character when style is bold.
m_baselineOffset = 0 ; // Used by subscript characters.
m_baselineOffsetStack . Clear ( ) ;
// Underline
bool beginUnderline = false ;
Vector3 underline_start = Vector3 . zero ; // Used to track where underline starts & ends.
Vector3 underline_end = Vector3 . zero ;
// Strike-through
bool beginStrikethrough = false ;
Vector3 strikethrough_start = Vector3 . zero ;
Vector3 strikethrough_end = Vector3 . zero ;
// Text Highlight
bool beginHighlight = false ;
Vector3 highlight_start = Vector3 . zero ;
Vector3 highlight_end = Vector3 . zero ;
m_fontColor32 = m_fontColor ;
Color32 vertexColor ;
m_htmlColor = m_fontColor32 ;
m_underlineColor = m_htmlColor ;
m_strikethroughColor = m_htmlColor ;
m_colorStack . SetDefault ( m_htmlColor ) ;
m_underlineColorStack . SetDefault ( m_htmlColor ) ;
m_strikethroughColorStack . SetDefault ( m_htmlColor ) ;
m_HighlightStateStack . SetDefault ( new HighlightState ( m_htmlColor , TMP_Offset . zero ) ) ;
m_colorGradientPreset = null ;
m_colorGradientStack . SetDefault ( null ) ;
m_ItalicAngle = m_currentFontAsset . italicStyle ;
m_ItalicAngleStack . SetDefault ( m_ItalicAngle ) ;
// Clear the Style stack.
//m_styleStack.Clear();
// Clear the Action stack.
m_actionStack . Clear ( ) ;
m_isFXMatrixSet = false ;
m_lineOffset = 0 ; // Amount of space between lines (font line spacing + m_linespacing).
m_lineHeight = TMP_Math . FLOAT_UNSET ;
float lineGap = m_currentFontAsset . m_FaceInfo . lineHeight - ( m_currentFontAsset . m_FaceInfo . ascentLine - m_currentFontAsset . m_FaceInfo . descentLine ) ;
m_cSpacing = 0 ; // Amount of space added between characters as a result of the use of the <cspace> tag.
m_monoSpacing = 0 ;
m_xAdvance = 0 ; // Used to track the position of each character.
tag_LineIndent = 0 ; // Used for indentation of text.
tag_Indent = 0 ;
m_indentStack . SetDefault ( 0 ) ;
tag_NoParsing = false ;
//m_isIgnoringAlignment = false;
m_characterCount = 0 ; // Total characters in the char[]
// Tracking of line information
m_firstCharacterOfLine = m_firstVisibleCharacter ;
m_lastCharacterOfLine = 0 ;
m_firstVisibleCharacterOfLine = 0 ;
m_lastVisibleCharacterOfLine = 0 ;
m_maxLineAscender = k_LargeNegativeFloat ;
m_maxLineDescender = k_LargePositiveFloat ;
m_lineNumber = 0 ;
m_startOfLineAscender = 0 ;
m_startOfLineDescender = 0 ;
m_lineVisibleCharacterCount = 0 ;
bool isStartOfNewLine = true ;
m_IsDrivenLineSpacing = false ;
m_firstOverflowCharacterIndex = - 1 ;
m_pageNumber = 0 ;
int pageToDisplay = Mathf . Clamp ( m_pageToDisplay - 1 , 0 , m_textInfo . pageInfo . Length - 1 ) ;
m_textInfo . ClearPageInfo ( ) ;
Vector4 margins = m_margin ;
float marginWidth = m_marginWidth > 0 ? m_marginWidth : 0 ;
float marginHeight = m_marginHeight > 0 ? m_marginHeight : 0 ;
m_marginLeft = 0 ;
m_marginRight = 0 ;
m_width = - 1 ;
float widthOfTextArea = marginWidth + 0.0001f - m_marginLeft - m_marginRight ;
// Need to initialize these Extents structures
m_meshExtents . min = k_LargePositiveVector2 ;
m_meshExtents . max = k_LargeNegativeVector2 ;
// Initialize lineInfo
m_textInfo . ClearLineInfo ( ) ;
// Tracking of the highest Ascender
m_maxCapHeight = 0 ;
m_maxTextAscender = 0 ;
m_ElementDescender = 0 ;
m_PageAscender = 0 ;
float maxVisibleDescender = 0 ;
bool isMaxVisibleDescenderSet = false ;
m_isNewPage = false ;
// Initialize struct to track states of word wrapping
bool isFirstWordOfLine = true ;
m_isNonBreakingSpace = false ;
bool ignoreNonBreakingSpace = false ;
//bool isLastCharacterCJK = false;
int lastSoftLineBreak = 0 ;
CharacterSubstitution characterToSubstitute = new CharacterSubstitution ( - 1 , 0 ) ;
bool isSoftHyphenIgnored = false ;
// Save character and line state before we begin layout.
SaveWordWrappingState ( ref m_SavedWordWrapState , - 1 , - 1 ) ;
SaveWordWrappingState ( ref m_SavedLineState , - 1 , - 1 ) ;
SaveWordWrappingState ( ref m_SavedEllipsisState , - 1 , - 1 ) ;
SaveWordWrappingState ( ref m_SavedLastValidState , - 1 , - 1 ) ;
SaveWordWrappingState ( ref m_SavedSoftLineBreakState , - 1 , - 1 ) ;
m_EllipsisInsertionCandidateStack . Clear ( ) ;
// Safety Tracker
int restoreCount = 0 ;
2022-01-12 10:39:15 +03:00
k_GenerateTextPhaseIMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Parse through Character buffer to read HTML tags and begin creating mesh.
2022-01-12 10:39:15 +03:00
for ( int i = 0 ; i < m_TextProcessingArray . Length & & m_TextProcessingArray [ i ] . unicode ! = 0 ; i + + )
2022-01-12 10:06:03 +03:00
{
2022-01-12 10:39:15 +03:00
charCode = m_TextProcessingArray [ i ] . unicode ;
2022-01-12 10:06:03 +03:00
if ( restoreCount > 5 )
{
Debug . LogError ( "Line breaking recursion max threshold hit... Character [" + charCode + "] index: " + i ) ;
characterToSubstitute . index = m_characterCount ;
characterToSubstitute . unicode = 0x03 ;
}
// Parse Rich Text Tag
#region Parse Rich Text Tag
if ( m_isRichText & & charCode = = 60 ) // '<'
{
2022-01-12 10:39:15 +03:00
k_ParseMarkupTextMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
m_isParsingText = true ;
m_textElementType = TMP_TextElementType . Character ;
int endTagIndex ;
// Check if Tag is valid. If valid, skip to the end of the validated tag.
2022-01-12 10:39:15 +03:00
if ( ValidateHtmlTag ( m_TextProcessingArray , i + 1 , out endTagIndex ) )
2022-01-12 10:06:03 +03:00
{
i = endTagIndex ;
// Continue to next character or handle the sprite element
if ( m_textElementType = = TMP_TextElementType . Character )
{
2022-01-12 10:39:15 +03:00
k_ParseMarkupTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
}
2022-01-12 10:39:15 +03:00
k_ParseMarkupTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
else
{
m_textElementType = m_textInfo . characterInfo [ m_characterCount ] . elementType ;
m_currentMaterialIndex = m_textInfo . characterInfo [ m_characterCount ] . materialReferenceIndex ;
m_currentFontAsset = m_textInfo . characterInfo [ m_characterCount ] . fontAsset ;
}
#endregion End Parse Rich Text Tag
int previousMaterialIndex = m_currentMaterialIndex ;
bool isUsingAltTypeface = m_textInfo . characterInfo [ m_characterCount ] . isUsingAlternateTypeface ;
m_isParsingText = false ;
// Handle potential character substitutions
#region Character Substitutions
2022-01-12 10:39:15 +03:00
bool isInjectingCharacter = false ;
2022-01-12 10:06:03 +03:00
if ( characterToSubstitute . index = = m_characterCount )
{
charCode = ( int ) characterToSubstitute . unicode ;
m_textElementType = TMP_TextElementType . Character ;
isInjectingCharacter = true ;
switch ( charCode )
{
case 0x03 :
m_textInfo . characterInfo [ m_characterCount ] . textElement = m_currentFontAsset . characterLookupTable [ 0x03 ] ;
m_isTextTruncated = true ;
break ;
case 0x2D :
/ /
break ;
case 0x2026 :
m_textInfo . characterInfo [ m_characterCount ] . textElement = m_Ellipsis . character ;
m_textInfo . characterInfo [ m_characterCount ] . elementType = TMP_TextElementType . Character ;
m_textInfo . characterInfo [ m_characterCount ] . fontAsset = m_Ellipsis . fontAsset ;
m_textInfo . characterInfo [ m_characterCount ] . material = m_Ellipsis . material ;
m_textInfo . characterInfo [ m_characterCount ] . materialReferenceIndex = m_Ellipsis . materialIndex ;
// Indicates the source parsing data has been modified.
m_isTextTruncated = true ;
// End Of Text
characterToSubstitute . index = m_characterCount + 1 ;
characterToSubstitute . unicode = 0x03 ;
break ;
}
}
#endregion
// When using Linked text, mark character as ignored and skip to next character.
#region Linked Text
if ( m_characterCount < m_firstVisibleCharacter & & charCode ! = 0x03 )
{
m_textInfo . characterInfo [ m_characterCount ] . isVisible = false ;
m_textInfo . characterInfo [ m_characterCount ] . character = ( char ) 0x200B ;
m_textInfo . characterInfo [ m_characterCount ] . lineNumber = 0 ;
m_characterCount + = 1 ;
continue ;
}
#endregion
// Handle Font Styles like LowerCase, UpperCase and SmallCaps.
#region Handling of LowerCase , UpperCase and SmallCaps Font Styles
float smallCapsMultiplier = 1.0f ;
if ( m_textElementType = = TMP_TextElementType . Character )
{
if ( ( m_FontStyleInternal & FontStyles . UpperCase ) = = FontStyles . UpperCase )
{
// If this character is lowercase, switch to uppercase.
if ( char . IsLower ( ( char ) charCode ) )
charCode = char . ToUpper ( ( char ) charCode ) ;
}
else if ( ( m_FontStyleInternal & FontStyles . LowerCase ) = = FontStyles . LowerCase )
{
// If this character is uppercase, switch to lowercase.
if ( char . IsUpper ( ( char ) charCode ) )
charCode = char . ToLower ( ( char ) charCode ) ;
}
else if ( ( m_FontStyleInternal & FontStyles . SmallCaps ) = = FontStyles . SmallCaps )
{
if ( char . IsLower ( ( char ) charCode ) )
{
smallCapsMultiplier = 0.8f ;
charCode = char . ToUpper ( ( char ) charCode ) ;
}
}
}
#endregion
// Look up Character Data from Dictionary and cache it.
#region Look up Character Data
2022-01-12 10:39:15 +03:00
k_CharacterLookupMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
float baselineOffset = 0 ;
float elementAscentLine = 0 ;
float elementDescentLine = 0 ;
if ( m_textElementType = = TMP_TextElementType . Sprite )
{
// If a sprite is used as a fallback then get a reference to it and set the color to white.
m_currentSpriteAsset = m_textInfo . characterInfo [ m_characterCount ] . spriteAsset ;
m_spriteIndex = m_textInfo . characterInfo [ m_characterCount ] . spriteIndex ;
TMP_SpriteCharacter sprite = m_currentSpriteAsset . spriteCharacterTable [ m_spriteIndex ] ;
2022-01-12 10:39:15 +03:00
if ( sprite = = null )
{
k_CharacterLookupMarker . End ( ) ;
continue ;
}
2022-01-12 10:06:03 +03:00
// Sprites are assigned in the E000 Private Area + sprite Index
if ( charCode = = 60 )
charCode = 57344 + m_spriteIndex ;
else
m_spriteColor = s_colorWhite ;
2022-01-12 10:39:15 +03:00
float fontScale = ( m_currentFontSize / m_currentFontAsset . faceInfo . pointSize * m_currentFontAsset . faceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ) ;
2022-01-12 10:06:03 +03:00
// The sprite scale calculations are based on the font asset assigned to the text object.
if ( m_currentSpriteAsset . m_FaceInfo . pointSize > 0 )
{
float spriteScale = m_currentFontSize / m_currentSpriteAsset . m_FaceInfo . pointSize * m_currentSpriteAsset . m_FaceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ;
currentElementScale = sprite . m_Scale * sprite . m_Glyph . scale * spriteScale ;
elementAscentLine = m_currentSpriteAsset . m_FaceInfo . ascentLine ;
2022-01-12 10:39:15 +03:00
baselineOffset = m_currentSpriteAsset . m_FaceInfo . baseline * fontScale * m_fontScaleMultiplier * m_currentSpriteAsset . m_FaceInfo . scale ;
2022-01-12 10:06:03 +03:00
elementDescentLine = m_currentSpriteAsset . m_FaceInfo . descentLine ;
}
else
{
float spriteScale = m_currentFontSize / m_currentFontAsset . m_FaceInfo . pointSize * m_currentFontAsset . m_FaceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ;
currentElementScale = m_currentFontAsset . m_FaceInfo . ascentLine / sprite . m_Glyph . metrics . height * sprite . m_Scale * sprite . m_Glyph . scale * spriteScale ;
float scaleDelta = spriteScale / currentElementScale ;
elementAscentLine = m_currentFontAsset . m_FaceInfo . ascentLine * scaleDelta ;
2022-01-12 10:39:15 +03:00
baselineOffset = m_currentFontAsset . m_FaceInfo . baseline * fontScale * m_fontScaleMultiplier * m_currentFontAsset . m_FaceInfo . scale ;
2022-01-12 10:06:03 +03:00
elementDescentLine = m_currentFontAsset . m_FaceInfo . descentLine * scaleDelta ;
}
m_cached_TextElement = sprite ;
m_textInfo . characterInfo [ m_characterCount ] . elementType = TMP_TextElementType . Sprite ;
m_textInfo . characterInfo [ m_characterCount ] . scale = currentElementScale ;
m_textInfo . characterInfo [ m_characterCount ] . spriteAsset = m_currentSpriteAsset ;
m_textInfo . characterInfo [ m_characterCount ] . fontAsset = m_currentFontAsset ;
m_textInfo . characterInfo [ m_characterCount ] . materialReferenceIndex = m_currentMaterialIndex ;
m_currentMaterialIndex = previousMaterialIndex ;
padding = 0 ;
}
else if ( m_textElementType = = TMP_TextElementType . Character )
{
m_cached_TextElement = m_textInfo . characterInfo [ m_characterCount ] . textElement ;
2022-01-12 10:39:15 +03:00
if ( m_cached_TextElement = = null )
{
k_CharacterLookupMarker . End ( ) ;
continue ;
}
2022-01-12 10:06:03 +03:00
m_currentFontAsset = m_textInfo . characterInfo [ m_characterCount ] . fontAsset ;
m_currentMaterial = m_textInfo . characterInfo [ m_characterCount ] . material ;
m_currentMaterialIndex = m_textInfo . characterInfo [ m_characterCount ] . materialReferenceIndex ;
// Special handling if replaced character was a line feed where in this case we have to use the scale of the previous character.
float adjustedScale ;
2022-01-12 10:39:15 +03:00
if ( isInjectingCharacter & & m_TextProcessingArray [ i ] . unicode = = 0x0A & & m_characterCount ! = m_firstCharacterOfLine )
2022-01-12 10:06:03 +03:00
adjustedScale = m_textInfo . characterInfo [ m_characterCount - 1 ] . pointSize * smallCapsMultiplier / m_currentFontAsset . m_FaceInfo . pointSize * m_currentFontAsset . m_FaceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ;
else
adjustedScale = m_currentFontSize * smallCapsMultiplier / m_currentFontAsset . m_FaceInfo . pointSize * m_currentFontAsset . m_FaceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ;
2022-01-12 10:39:15 +03:00
// Special handling for injected Ellipsis
if ( isInjectingCharacter & & charCode = = 0x2026 )
{
elementAscentLine = 0 ;
elementDescentLine = 0 ;
}
else
{
elementAscentLine = m_currentFontAsset . m_FaceInfo . ascentLine ;
elementDescentLine = m_currentFontAsset . m_FaceInfo . descentLine ;
}
2022-01-12 10:06:03 +03:00
currentElementScale = adjustedScale * m_fontScaleMultiplier * m_cached_TextElement . m_Scale * m_cached_TextElement . m_Glyph . scale ;
baselineOffset = m_currentFontAsset . m_FaceInfo . baseline * adjustedScale * m_fontScaleMultiplier * m_currentFontAsset . m_FaceInfo . scale ;
m_textInfo . characterInfo [ m_characterCount ] . elementType = TMP_TextElementType . Character ;
m_textInfo . characterInfo [ m_characterCount ] . scale = currentElementScale ;
padding = m_currentMaterialIndex = = 0 ? m_padding : m_subTextObjects [ m_currentMaterialIndex ] . padding ;
}
2022-01-12 10:39:15 +03:00
k_CharacterLookupMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
#endregion
// Handle Soft Hyphen
#region Handle Soft Hyphen
float currentElementUnmodifiedScale = currentElementScale ;
if ( charCode = = 0xAD | | charCode = = 0x03 )
currentElementScale = 0 ;
#endregion
// Store some of the text object's information
m_textInfo . characterInfo [ m_characterCount ] . character = ( char ) charCode ;
m_textInfo . characterInfo [ m_characterCount ] . pointSize = m_currentFontSize ;
m_textInfo . characterInfo [ m_characterCount ] . color = m_htmlColor ;
m_textInfo . characterInfo [ m_characterCount ] . underlineColor = m_underlineColor ;
m_textInfo . characterInfo [ m_characterCount ] . strikethroughColor = m_strikethroughColor ;
m_textInfo . characterInfo [ m_characterCount ] . highlightState = m_HighlightStateStack . current ;
m_textInfo . characterInfo [ m_characterCount ] . style = m_FontStyleInternal ;
// Cache glyph metrics
GlyphMetrics currentGlyphMetrics = m_cached_TextElement . m_Glyph . metrics ;
// Optimization to avoid calling this more than once per character.
2022-01-12 10:39:15 +03:00
bool isWhiteSpace = charCode < = 0xFFFF & & char . IsWhiteSpace ( ( char ) charCode ) ;
2022-01-12 10:06:03 +03:00
// Handle Kerning if Enabled.
#region Handle Kerning
TMP_GlyphValueRecord glyphAdjustments = new TMP_GlyphValueRecord ( ) ;
float characterSpacingAdjustment = m_characterSpacing ;
m_GlyphHorizontalAdvanceAdjustment = 0 ;
if ( m_enableKerning )
{
2022-01-12 10:39:15 +03:00
k_HandleGPOSFeaturesMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
TMP_GlyphPairAdjustmentRecord adjustmentPair ;
uint baseGlyphIndex = m_cached_TextElement . m_GlyphIndex ;
if ( m_characterCount < totalCharacterCount - 1 )
{
uint nextGlyphIndex = m_textInfo . characterInfo [ m_characterCount + 1 ] . textElement . m_GlyphIndex ;
uint key = nextGlyphIndex < < 16 | baseGlyphIndex ;
if ( m_currentFontAsset . m_FontFeatureTable . m_GlyphPairAdjustmentRecordLookupDictionary . TryGetValue ( key , out adjustmentPair ) )
{
glyphAdjustments = adjustmentPair . m_FirstAdjustmentRecord . m_GlyphValueRecord ;
characterSpacingAdjustment = ( adjustmentPair . m_FeatureLookupFlags & FontFeatureLookupFlags . IgnoreSpacingAdjustments ) = = FontFeatureLookupFlags . IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment ;
}
}
if ( m_characterCount > = 1 )
{
uint previousGlyphIndex = m_textInfo . characterInfo [ m_characterCount - 1 ] . textElement . m_GlyphIndex ;
uint key = baseGlyphIndex < < 16 | previousGlyphIndex ;
if ( m_currentFontAsset . m_FontFeatureTable . m_GlyphPairAdjustmentRecordLookupDictionary . TryGetValue ( key , out adjustmentPair ) )
{
glyphAdjustments + = adjustmentPair . m_SecondAdjustmentRecord . m_GlyphValueRecord ;
characterSpacingAdjustment = ( adjustmentPair . m_FeatureLookupFlags & FontFeatureLookupFlags . IgnoreSpacingAdjustments ) = = FontFeatureLookupFlags . IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment ;
}
}
2022-01-12 10:39:15 +03:00
m_GlyphHorizontalAdvanceAdjustment = glyphAdjustments . xAdvance ;
k_HandleGPOSFeaturesMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
#endregion
// Initial Implementation for RTL support.
#region Handle Right - to - Left
if ( m_isRightToLeft )
{
m_xAdvance - = currentGlyphMetrics . horizontalAdvance * ( 1 - m_charWidthAdjDelta ) * currentElementScale ;
if ( isWhiteSpace | | charCode = = 0x200B )
m_xAdvance - = m_wordSpacing * currentEmScale ;
}
#endregion
// Handle Mono Spacing
#region Handle Mono Spacing
float monoAdvance = 0 ;
if ( m_monoSpacing ! = 0 )
{
monoAdvance = ( m_monoSpacing / 2 - ( currentGlyphMetrics . width / 2 + currentGlyphMetrics . horizontalBearingX ) * currentElementScale ) * ( 1 - m_charWidthAdjDelta ) ;
m_xAdvance + = monoAdvance ;
}
#endregion
// Set Padding based on selected font style
#region Handle Style Padding
if ( m_textElementType = = TMP_TextElementType . Character & & ! isUsingAltTypeface & & ( ( m_FontStyleInternal & FontStyles . Bold ) = = FontStyles . Bold ) ) // Checks for any combination of Bold Style.
{
if ( m_currentMaterial ! = null & & m_currentMaterial . HasProperty ( ShaderUtilities . ID_GradientScale ) )
{
float gradientScale = m_currentMaterial . GetFloat ( ShaderUtilities . ID_GradientScale ) ;
style_padding = m_currentFontAsset . boldStyle / 4.0f * gradientScale * m_currentMaterial . GetFloat ( ShaderUtilities . ID_ScaleRatio_A ) ;
// Clamp overall padding to Gradient Scale size.
if ( style_padding + padding > gradientScale )
padding = gradientScale - style_padding ;
}
else
style_padding = 0 ;
boldSpacingAdjustment = m_currentFontAsset . boldSpacing ;
}
else
{
2022-01-12 10:39:15 +03:00
if ( m_currentMaterial ! = null & & m_currentMaterial . HasProperty ( ShaderUtilities . ID_GradientScale ) & & m_currentMaterial . HasProperty ( ShaderUtilities . ID_ScaleRatio_A ) )
2022-01-12 10:06:03 +03:00
{
float gradientScale = m_currentMaterial . GetFloat ( ShaderUtilities . ID_GradientScale ) ;
style_padding = m_currentFontAsset . normalStyle / 4.0f * gradientScale * m_currentMaterial . GetFloat ( ShaderUtilities . ID_ScaleRatio_A ) ;
// Clamp overall padding to Gradient Scale size.
if ( style_padding + padding > gradientScale )
padding = gradientScale - style_padding ;
}
else
style_padding = 0 ;
boldSpacingAdjustment = 0 ;
}
#endregion Handle Style Padding
// Determine the position of the vertices of the Character or Sprite.
#region Calculate Vertices Position
2022-01-12 10:39:15 +03:00
k_CalculateVerticesPositionMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
Vector3 top_left ;
top_left . x = m_xAdvance + ( ( currentGlyphMetrics . horizontalBearingX - padding - style_padding + glyphAdjustments . m_XPlacement ) * currentElementScale * ( 1 - m_charWidthAdjDelta ) ) ;
top_left . y = baselineOffset + ( currentGlyphMetrics . horizontalBearingY + padding + glyphAdjustments . m_YPlacement ) * currentElementScale - m_lineOffset + m_baselineOffset ;
top_left . z = 0 ;
Vector3 bottom_left ;
bottom_left . x = top_left . x ;
bottom_left . y = top_left . y - ( ( currentGlyphMetrics . height + padding * 2 ) * currentElementScale ) ;
bottom_left . z = 0 ;
Vector3 top_right ;
top_right . x = bottom_left . x + ( ( currentGlyphMetrics . width + padding * 2 + style_padding * 2 ) * currentElementScale * ( 1 - m_charWidthAdjDelta ) ) ;
top_right . y = top_left . y ;
top_right . z = 0 ;
Vector3 bottom_right ;
bottom_right . x = top_right . x ;
bottom_right . y = bottom_left . y ;
bottom_right . z = 0 ;
2022-01-12 10:39:15 +03:00
k_CalculateVerticesPositionMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
#endregion
// Check if we need to Shear the rectangles for Italic styles
#region Handle Italic & Shearing
if ( m_textElementType = = TMP_TextElementType . Character & & ! isUsingAltTypeface & & ( ( m_FontStyleInternal & FontStyles . Italic ) = = FontStyles . Italic ) )
{
// Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount.
float shear_value = m_ItalicAngle * 0.01f ;
Vector3 topShear = new Vector3 ( shear_value * ( ( currentGlyphMetrics . horizontalBearingY + padding + style_padding ) * currentElementScale ) , 0 , 0 ) ;
Vector3 bottomShear = new Vector3 ( shear_value * ( ( ( currentGlyphMetrics . horizontalBearingY - currentGlyphMetrics . height - padding - style_padding ) ) * currentElementScale ) , 0 , 0 ) ;
Vector3 shearAdjustment = new Vector3 ( ( topShear . x - bottomShear . x ) / 2 , 0 , 0 ) ;
top_left = top_left + topShear - shearAdjustment ;
bottom_left = bottom_left + bottomShear - shearAdjustment ;
top_right = top_right + topShear - shearAdjustment ;
bottom_right = bottom_right + bottomShear - shearAdjustment ;
}
#endregion Handle Italics & Shearing
// Handle Character Rotation
#region Handle Character Rotation
if ( m_isFXMatrixSet )
{
// Apply scale matrix when simulating Condensed text.
if ( m_FXMatrix . lossyScale . x ! = 1 )
{
//top_left = m_FXMatrix.MultiplyPoint3x4(top_left);
//bottom_left = m_FXMatrix.MultiplyPoint3x4(bottom_left);
//top_right = m_FXMatrix.MultiplyPoint3x4(top_right);
//bottom_right = m_FXMatrix.MultiplyPoint3x4(bottom_right);
}
Vector3 positionOffset = ( top_right + bottom_left ) / 2 ;
top_left = m_FXMatrix . MultiplyPoint3x4 ( top_left - positionOffset ) + positionOffset ;
bottom_left = m_FXMatrix . MultiplyPoint3x4 ( bottom_left - positionOffset ) + positionOffset ;
top_right = m_FXMatrix . MultiplyPoint3x4 ( top_right - positionOffset ) + positionOffset ;
bottom_right = m_FXMatrix . MultiplyPoint3x4 ( bottom_right - positionOffset ) + positionOffset ;
}
#endregion
// Store vertex information for the character or sprite.
m_textInfo . characterInfo [ m_characterCount ] . bottomLeft = bottom_left ;
m_textInfo . characterInfo [ m_characterCount ] . topLeft = top_left ;
m_textInfo . characterInfo [ m_characterCount ] . topRight = top_right ;
m_textInfo . characterInfo [ m_characterCount ] . bottomRight = bottom_right ;
m_textInfo . characterInfo [ m_characterCount ] . origin = m_xAdvance ;
m_textInfo . characterInfo [ m_characterCount ] . baseLine = baselineOffset - m_lineOffset + m_baselineOffset ;
m_textInfo . characterInfo [ m_characterCount ] . aspectRatio = ( top_right . x - bottom_left . x ) / ( top_left . y - bottom_left . y ) ;
// Compute text metrics
#region Compute Ascender & Descender values
2022-01-12 10:39:15 +03:00
k_ComputeTextMetricsMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Element Ascender in line space
float elementAscender = m_textElementType = = TMP_TextElementType . Character
? elementAscentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset
: elementAscentLine * currentElementScale + m_baselineOffset ;
// Element Descender in line space
float elementDescender = m_textElementType = = TMP_TextElementType . Character
? elementDescentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset
: elementDescentLine * currentElementScale + m_baselineOffset ;
float adjustedAscender = elementAscender ;
float adjustedDescender = elementDescender ;
bool isFirstCharacterOfLine = m_characterCount = = m_firstCharacterOfLine ;
// Max line ascender and descender in line space
if ( isFirstCharacterOfLine | | isWhiteSpace = = false )
{
// Special handling for Superscript and Subscript where we use the unadjusted line ascender and descender
if ( m_baselineOffset ! = 0 )
{
adjustedAscender = Mathf . Max ( ( elementAscender - m_baselineOffset ) / m_fontScaleMultiplier , adjustedAscender ) ;
adjustedDescender = Mathf . Min ( ( elementDescender - m_baselineOffset ) / m_fontScaleMultiplier , adjustedDescender ) ;
}
m_maxLineAscender = Mathf . Max ( adjustedAscender , m_maxLineAscender ) ;
m_maxLineDescender = Mathf . Min ( adjustedDescender , m_maxLineDescender ) ;
}
// Element Ascender and Descender in object space
if ( isFirstCharacterOfLine | | isWhiteSpace = = false )
{
m_textInfo . characterInfo [ m_characterCount ] . adjustedAscender = adjustedAscender ;
m_textInfo . characterInfo [ m_characterCount ] . adjustedDescender = adjustedDescender ;
m_ElementAscender = m_textInfo . characterInfo [ m_characterCount ] . ascender = elementAscender - m_lineOffset ;
m_ElementDescender = m_textInfo . characterInfo [ m_characterCount ] . descender = elementDescender - m_lineOffset ;
}
else
{
m_textInfo . characterInfo [ m_characterCount ] . adjustedAscender = m_maxLineAscender ;
m_textInfo . characterInfo [ m_characterCount ] . adjustedDescender = m_maxLineDescender ;
m_ElementAscender = m_textInfo . characterInfo [ m_characterCount ] . ascender = m_maxLineAscender - m_lineOffset ;
m_ElementDescender = m_textInfo . characterInfo [ m_characterCount ] . descender = m_maxLineDescender - m_lineOffset ;
}
// Max text object ascender and cap height
if ( m_lineNumber = = 0 | | m_isNewPage )
{
if ( isFirstCharacterOfLine | | isWhiteSpace = = false )
{
m_maxTextAscender = m_maxLineAscender ;
m_maxCapHeight = Mathf . Max ( m_maxCapHeight , m_currentFontAsset . m_FaceInfo . capLine * currentElementScale / smallCapsMultiplier ) ;
}
}
// Page ascender
if ( m_lineOffset = = 0 )
{
if ( isFirstCharacterOfLine | | isWhiteSpace = = false )
m_PageAscender = m_PageAscender > elementAscender ? m_PageAscender : elementAscender ;
}
2022-01-12 10:39:15 +03:00
k_ComputeTextMetricsMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
#endregion
// Set Characters to not visible by default.
m_textInfo . characterInfo [ m_characterCount ] . isVisible = false ;
bool isJustifiedOrFlush = ( m_lineJustification & HorizontalAlignmentOptions . Flush ) = = HorizontalAlignmentOptions . Flush | | ( m_lineJustification & HorizontalAlignmentOptions . Justified ) = = HorizontalAlignmentOptions . Justified ;
// Setup Mesh for visible text elements. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
#region Handle Visible Characters
if ( charCode = = 9 | | ( isWhiteSpace = = false & & charCode ! = 0x200B & & charCode ! = 0xAD & & charCode ! = 0x03 ) | | ( charCode = = 0xAD & & isSoftHyphenIgnored = = false ) | | m_textElementType = = TMP_TextElementType . Sprite )
{
2022-01-12 10:39:15 +03:00
k_HandleVisibleCharacterMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
m_textInfo . characterInfo [ m_characterCount ] . isVisible = true ;
#region Experimental Margin Shaper
//Vector2 shapedMargins;
//if (marginShaper)
//{
// shapedMargins = m_marginShaper.GetShapedMargins(m_textInfo.characterInfo[m_characterCount].baseLine);
// if (shapedMargins.x < margins.x)
// {
// shapedMargins.x = m_marginLeft;
// }
// else
// {
// shapedMargins.x += m_marginLeft - margins.x;
// }
// if (shapedMargins.y < margins.z)
// {
// shapedMargins.y = m_marginRight;
// }
// else
// {
// shapedMargins.y += m_marginRight - margins.z;
// }
//}
//else
//{
// shapedMargins.x = m_marginLeft;
// shapedMargins.y = m_marginRight;
//}
//width = marginWidth + 0.0001f - shapedMargins.x - shapedMargins.y;
//if (m_width != -1 && m_width < width)
//{
// width = m_width;
//}
//m_textInfo.lineInfo[m_lineNumber].marginLeft = shapedMargins.x;
#endregion
float marginLeft = m_marginLeft ;
float marginRight = m_marginRight ;
// Injected characters do not override margins
if ( isInjectingCharacter )
{
marginLeft = m_textInfo . lineInfo [ m_lineNumber ] . marginLeft ;
marginRight = m_textInfo . lineInfo [ m_lineNumber ] . marginRight ;
}
widthOfTextArea = m_width ! = - 1 ? Mathf . Min ( marginWidth + 0.0001f - marginLeft - marginRight , m_width ) : marginWidth + 0.0001f - marginLeft - marginRight ;
// Calculate the line breaking width of the text.
float textWidth = Mathf . Abs ( m_xAdvance ) + ( ! m_isRightToLeft ? currentGlyphMetrics . horizontalAdvance : 0 ) * ( 1 - m_charWidthAdjDelta ) * ( charCode = = 0xAD ? currentElementUnmodifiedScale : currentElementScale ) ;
float textHeight = m_maxTextAscender - ( m_maxLineDescender - m_lineOffset ) + ( m_lineOffset > 0 & & m_IsDrivenLineSpacing = = false ? m_maxLineAscender - m_startOfLineAscender : 0 ) ;
int testedCharacterCount = m_characterCount ;
// Handling of current line Vertical Bounds
#region Current Line Vertical Bounds Check
if ( textHeight > marginHeight + 0.0001f )
{
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Set isTextOverflowing and firstOverflowCharacterIndex
if ( m_firstOverflowCharacterIndex = = - 1 )
m_firstOverflowCharacterIndex = m_characterCount ;
// Check if Auto-Size is enabled
if ( m_enableAutoSizing )
{
// Handle Line spacing adjustments
#region Line Spacing Adjustments
if ( m_lineSpacingDelta > m_lineSpacingMax & & m_lineOffset > 0 & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
float adjustmentDelta = ( marginHeight - textHeight ) / m_lineNumber ;
m_lineSpacingDelta = Mathf . Max ( m_lineSpacingDelta + adjustmentDelta / baseScale , m_lineSpacingMax ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Line Spacing. Delta of [" + m_lineSpacingDelta.ToString("f3") + "].");
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion
// Handle Text Auto-sizing resulting from text exceeding vertical bounds.
#region Text Auto - Sizing ( Text greater than vertical bounds )
if ( m_fontSize > m_fontSizeMin & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
m_maxFontSize = m_fontSize ;
float sizeDelta = Mathf . Max ( ( m_fontSize - m_minFontSize ) / 2 , 0.05f ) ;
m_fontSize - = sizeDelta ;
m_fontSize = Mathf . Max ( ( int ) ( m_fontSize * 20 + 0.5f ) / 20f , m_fontSizeMin ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion Text Auto - Sizing
}
// Handle Vertical Overflow on current line
switch ( m_overflowMode )
{
case TextOverflowModes . Overflow :
case TextOverflowModes . ScrollRect :
case TextOverflowModes . Masking :
// Nothing happens as vertical bounds are ignored in this mode.
break ;
case TextOverflowModes . Truncate :
i = RestoreWordWrappingState ( ref m_SavedLastValidState ) ;
characterToSubstitute . index = testedCharacterCount ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Ellipsis :
if ( m_EllipsisInsertionCandidateStack . Count = = 0 )
{
i = - 1 ;
m_characterCount = 0 ;
characterToSubstitute . index = 0 ;
characterToSubstitute . unicode = 0x03 ;
m_firstCharacterOfLine = 0 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
var ellipsisState = m_EllipsisInsertionCandidateStack . Pop ( ) ;
i = RestoreWordWrappingState ( ref ellipsisState ) ;
i - = 1 ;
m_characterCount - = 1 ;
characterToSubstitute . index = m_characterCount ;
characterToSubstitute . unicode = 0x2026 ;
restoreCount + = 1 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Linked :
i = RestoreWordWrappingState ( ref m_SavedLastValidState ) ;
if ( m_linkedTextComponent ! = null )
{
m_linkedTextComponent . text = text ;
2022-01-12 10:39:15 +03:00
m_linkedTextComponent . m_inputSource = m_inputSource ;
2022-01-12 10:06:03 +03:00
m_linkedTextComponent . firstVisibleCharacter = m_characterCount ;
m_linkedTextComponent . ForceMeshUpdate ( ) ;
m_isTextTruncated = true ;
}
// Truncate remaining text
characterToSubstitute . index = testedCharacterCount ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Page :
// End layout of text if first character / page doesn't fit.
if ( i < 0 | | testedCharacterCount = = 0 )
{
i = - 1 ;
m_characterCount = 0 ;
characterToSubstitute . index = 0 ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
else if ( m_maxLineAscender - m_maxLineDescender > marginHeight + 0.0001f )
{
// Current line exceeds the height of the text container
// as such we stop on the previous line.
i = RestoreWordWrappingState ( ref m_SavedLineState ) ;
characterToSubstitute . index = testedCharacterCount ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
// Go back to previous line and re-layout
i = RestoreWordWrappingState ( ref m_SavedLineState ) ;
m_isNewPage = true ;
m_firstCharacterOfLine = m_characterCount ;
m_maxLineAscender = k_LargeNegativeFloat ;
m_maxLineDescender = k_LargePositiveFloat ;
m_startOfLineAscender = 0 ;
m_xAdvance = 0 + tag_Indent ;
m_lineOffset = 0 ;
m_maxTextAscender = 0 ;
m_PageAscender = 0 ;
m_lineNumber + = 1 ;
m_pageNumber + = 1 ;
// Should consider saving page data here
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
#endregion
// Handling of Horizontal Bounds
#region Current Line Horizontal Bounds Check
if ( textWidth > widthOfTextArea * ( isJustifiedOrFlush ? 1.05f : 1.0f ) )
{
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Handle Line Breaking (if still possible)
2022-01-12 10:39:15 +03:00
if ( m_enableWordWrapping & & m_characterCount ! = m_firstCharacterOfLine )
2022-01-12 10:06:03 +03:00
{
// Restore state to previous safe line breaking
i = RestoreWordWrappingState ( ref m_SavedWordWrapState ) ;
// Compute potential new line offset in the event a line break is needed.
float lineOffsetDelta = 0 ;
if ( m_lineHeight = = TMP_Math . FLOAT_UNSET )
{
float ascender = m_textInfo . characterInfo [ m_characterCount ] . adjustedAscender ;
lineOffsetDelta = ( m_lineOffset > 0 & & m_IsDrivenLineSpacing = = false ? m_maxLineAscender - m_startOfLineAscender : 0 ) - m_maxLineDescender + ascender + ( lineGap + m_lineSpacingDelta ) * baseScale + m_lineSpacing * currentEmScale ;
}
else
{
lineOffsetDelta = m_lineHeight + m_lineSpacing * currentEmScale ;
m_IsDrivenLineSpacing = true ;
}
// Calculate new text height
float newTextHeight = m_maxTextAscender + lineOffsetDelta + m_lineOffset - m_textInfo . characterInfo [ m_characterCount ] . adjustedDescender ;
// Replace Soft Hyphen by Hyphen Minus 0x2D
#region Handle Soft Hyphenation
if ( m_textInfo . characterInfo [ m_characterCount - 1 ] . character = = 0xAD & & isSoftHyphenIgnored = = false )
{
// Only inject Hyphen Minus if new line is possible
if ( m_overflowMode = = TextOverflowModes . Overflow | | newTextHeight < marginHeight + 0.0001f )
{
characterToSubstitute . index = m_characterCount - 1 ;
characterToSubstitute . unicode = 0x2D ;
i - = 1 ;
m_characterCount - = 1 ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
}
isSoftHyphenIgnored = false ;
// Ignore Soft Hyphen to prevent it from wrapping
if ( m_textInfo . characterInfo [ m_characterCount ] . character = = 0xAD )
{
isSoftHyphenIgnored = true ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
#endregion
// Adjust character spacing before breaking up word if auto size is enabled
if ( m_enableAutoSizing & & isFirstWordOfLine )
{
// Handle Character Width Adjustments
#region Character Width Adjustments
if ( m_charWidthAdjDelta < m_charWidthMaxAdj / 100 & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
float adjustedTextWidth = textWidth ;
// Determine full width of the text
if ( m_charWidthAdjDelta > 0 )
adjustedTextWidth / = 1f - m_charWidthAdjDelta ;
float adjustmentDelta = textWidth - ( widthOfTextArea - 0.0001f ) * ( isJustifiedOrFlush ? 1.05f : 1.0f ) ;
m_charWidthAdjDelta + = adjustmentDelta / adjustedTextWidth ;
m_charWidthAdjDelta = Mathf . Min ( m_charWidthAdjDelta , m_charWidthMaxAdj / 100 ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion
// Handle Text Auto-sizing resulting from text exceeding vertical bounds.
#region Text Auto - Sizing ( Text greater than vertical bounds )
if ( m_fontSize > m_fontSizeMin & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
m_maxFontSize = m_fontSize ;
float sizeDelta = Mathf . Max ( ( m_fontSize - m_minFontSize ) / 2 , 0.05f ) ;
m_fontSize - = sizeDelta ;
m_fontSize = Mathf . Max ( ( int ) ( m_fontSize * 20 + 0.5f ) / 20f , m_fontSizeMin ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion Text Auto - Sizing
}
// Special handling if first word of line and non breaking space
int savedSoftLineBreakingSpace = m_SavedSoftLineBreakState . previous_WordBreak ;
if ( isFirstWordOfLine & & savedSoftLineBreakingSpace ! = - 1 )
{
if ( savedSoftLineBreakingSpace ! = lastSoftLineBreak )
{
i = RestoreWordWrappingState ( ref m_SavedSoftLineBreakState ) ;
lastSoftLineBreak = savedSoftLineBreakingSpace ;
// check if soft hyphen
if ( m_textInfo . characterInfo [ m_characterCount - 1 ] . character = = 0xAD )
{
characterToSubstitute . index = m_characterCount - 1 ;
characterToSubstitute . unicode = 0x2D ;
i - = 1 ;
m_characterCount - = 1 ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
}
}
// Determine if new line of text would exceed the vertical bounds of text container
if ( newTextHeight > marginHeight + 0.0001f )
{
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Set isTextOverflowing and firstOverflowCharacterIndex
if ( m_firstOverflowCharacterIndex = = - 1 )
m_firstOverflowCharacterIndex = m_characterCount ;
// Check if Auto-Size is enabled
if ( m_enableAutoSizing )
{
// Handle Line spacing adjustments
#region Line Spacing Adjustments
if ( m_lineSpacingDelta > m_lineSpacingMax & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
float adjustmentDelta = ( marginHeight - newTextHeight ) / ( m_lineNumber + 1 ) ;
m_lineSpacingDelta = Mathf . Max ( m_lineSpacingDelta + adjustmentDelta / baseScale , m_lineSpacingMax ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Line Spacing. Delta of [" + m_lineSpacingDelta.ToString("f3") + "].");
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion
// Handle Character Width Adjustments
#region Character Width Adjustments
if ( m_charWidthAdjDelta < m_charWidthMaxAdj / 100 & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
float adjustedTextWidth = textWidth ;
// Determine full width of the text
if ( m_charWidthAdjDelta > 0 )
adjustedTextWidth / = 1f - m_charWidthAdjDelta ;
float adjustmentDelta = textWidth - ( widthOfTextArea - 0.0001f ) * ( isJustifiedOrFlush ? 1.05f : 1.0f ) ;
m_charWidthAdjDelta + = adjustmentDelta / adjustedTextWidth ;
m_charWidthAdjDelta = Mathf . Min ( m_charWidthAdjDelta , m_charWidthMaxAdj / 100 ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion
// Handle Text Auto-sizing resulting from text exceeding vertical bounds.
#region Text Auto - Sizing ( Text greater than vertical bounds )
if ( m_fontSize > m_fontSizeMin & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
m_maxFontSize = m_fontSize ;
float sizeDelta = Mathf . Max ( ( m_fontSize - m_minFontSize ) / 2 , 0.05f ) ;
m_fontSize - = sizeDelta ;
m_fontSize = Mathf . Max ( ( int ) ( m_fontSize * 20 + 0.5f ) / 20f , m_fontSizeMin ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion Text Auto - Sizing
}
// Check Text Overflow Modes
switch ( m_overflowMode )
{
case TextOverflowModes . Overflow :
case TextOverflowModes . ScrollRect :
case TextOverflowModes . Masking :
InsertNewLine ( i , baseScale , currentElementScale , currentEmScale , m_GlyphHorizontalAdvanceAdjustment , boldSpacingAdjustment , characterSpacingAdjustment , widthOfTextArea , lineGap , ref isMaxVisibleDescenderSet , ref maxVisibleDescender ) ;
isStartOfNewLine = true ;
isFirstWordOfLine = true ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Truncate :
i = RestoreWordWrappingState ( ref m_SavedLastValidState ) ;
characterToSubstitute . index = testedCharacterCount ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Ellipsis :
if ( m_EllipsisInsertionCandidateStack . Count = = 0 )
{
i = - 1 ;
m_characterCount = 0 ;
characterToSubstitute . index = 0 ;
characterToSubstitute . unicode = 0x03 ;
m_firstCharacterOfLine = 0 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
var ellipsisState = m_EllipsisInsertionCandidateStack . Pop ( ) ;
i = RestoreWordWrappingState ( ref ellipsisState ) ;
i - = 1 ;
m_characterCount - = 1 ;
characterToSubstitute . index = m_characterCount ;
characterToSubstitute . unicode = 0x2026 ;
restoreCount + = 1 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Linked :
if ( m_linkedTextComponent ! = null )
{
m_linkedTextComponent . text = text ;
2022-01-12 10:39:15 +03:00
m_linkedTextComponent . m_inputSource = m_inputSource ;
2022-01-12 10:06:03 +03:00
m_linkedTextComponent . firstVisibleCharacter = m_characterCount ;
m_linkedTextComponent . ForceMeshUpdate ( ) ;
m_isTextTruncated = true ;
}
// Truncate remaining text
characterToSubstitute . index = m_characterCount ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Page :
// Add new page
m_isNewPage = true ;
InsertNewLine ( i , baseScale , currentElementScale , currentEmScale , m_GlyphHorizontalAdvanceAdjustment , boldSpacingAdjustment , characterSpacingAdjustment , widthOfTextArea , lineGap , ref isMaxVisibleDescenderSet , ref maxVisibleDescender ) ;
m_startOfLineAscender = 0 ;
m_lineOffset = 0 ;
m_maxTextAscender = 0 ;
m_PageAscender = 0 ;
m_pageNumber + = 1 ;
isStartOfNewLine = true ;
isFirstWordOfLine = true ;
2022-01-12 10:39:15 +03:00
k_HandleVerticalLineBreakingMarker . End ( ) ;
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
}
else
{
//if (m_enableAutoSizing && isFirstWordOfLine)
//{
// // Handle Character Width Adjustments
// #region Character Width Adjustments
// if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
// {
// //m_AutoSizeIterationCount = 0;
// float adjustedTextWidth = textWidth;
// // Determine full width of the text
// if (m_charWidthAdjDelta > 0)
// adjustedTextWidth /= 1f - m_charWidthAdjDelta;
// float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
// m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
// m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
// //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
// GenerateTextMesh();
// return;
// }
// #endregion
//}
// New line of text does not exceed vertical bounds of text container
InsertNewLine ( i , baseScale , currentElementScale , currentEmScale , m_GlyphHorizontalAdvanceAdjustment , boldSpacingAdjustment , characterSpacingAdjustment , widthOfTextArea , lineGap , ref isMaxVisibleDescenderSet , ref maxVisibleDescender ) ;
isStartOfNewLine = true ;
isFirstWordOfLine = true ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
}
else
{
if ( m_enableAutoSizing & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
// Handle Character Width Adjustments
#region Character Width Adjustments
if ( m_charWidthAdjDelta < m_charWidthMaxAdj / 100 )
{
float adjustedTextWidth = textWidth ;
// Determine full width of the text
if ( m_charWidthAdjDelta > 0 )
adjustedTextWidth / = 1f - m_charWidthAdjDelta ;
float adjustmentDelta = textWidth - ( widthOfTextArea - 0.0001f ) * ( isJustifiedOrFlush ? 1.05f : 1.0f ) ;
m_charWidthAdjDelta + = adjustmentDelta / adjustedTextWidth ;
m_charWidthAdjDelta = Mathf . Min ( m_charWidthAdjDelta , m_charWidthMaxAdj / 100 ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion
// Handle Text Auto-sizing resulting from text exceeding horizontal bounds.
#region Text Exceeds Horizontal Bounds - Reducing Point Size
if ( m_fontSize > m_fontSizeMin )
{
// Reset character width adjustment delta
//m_charWidthAdjDelta = 0;
// Adjust Point Size
m_maxFontSize = m_fontSize ;
float sizeDelta = Mathf . Max ( ( m_fontSize - m_minFontSize ) / 2 , 0.05f ) ;
m_fontSize - = sizeDelta ;
m_fontSize = Mathf . Max ( ( int ) ( m_fontSize * 20 + 0.5f ) / 20f , m_fontSizeMin ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion
}
// Check Text Overflow Modes
switch ( m_overflowMode )
{
case TextOverflowModes . Overflow :
case TextOverflowModes . ScrollRect :
case TextOverflowModes . Masking :
// Nothing happens as horizontal bounds are ignored in this mode.
break ;
case TextOverflowModes . Truncate :
i = RestoreWordWrappingState ( ref m_SavedWordWrapState ) ;
characterToSubstitute . index = testedCharacterCount ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Ellipsis :
if ( m_EllipsisInsertionCandidateStack . Count = = 0 )
{
i = - 1 ;
m_characterCount = 0 ;
characterToSubstitute . index = 0 ;
characterToSubstitute . unicode = 0x03 ;
m_firstCharacterOfLine = 0 ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
var ellipsisState = m_EllipsisInsertionCandidateStack . Pop ( ) ;
i = RestoreWordWrappingState ( ref ellipsisState ) ;
i - = 1 ;
m_characterCount - = 1 ;
characterToSubstitute . index = m_characterCount ;
characterToSubstitute . unicode = 0x2026 ;
restoreCount + = 1 ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
case TextOverflowModes . Linked :
i = RestoreWordWrappingState ( ref m_SavedWordWrapState ) ;
if ( m_linkedTextComponent ! = null )
{
m_linkedTextComponent . text = text ;
2022-01-12 10:39:15 +03:00
m_linkedTextComponent . m_inputSource = m_inputSource ;
2022-01-12 10:06:03 +03:00
m_linkedTextComponent . firstVisibleCharacter = m_characterCount ;
m_linkedTextComponent . ForceMeshUpdate ( ) ;
m_isTextTruncated = true ;
}
// Truncate text the overflows the vertical bounds
characterToSubstitute . index = m_characterCount ;
characterToSubstitute . unicode = 0x03 ;
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
}
2022-01-12 10:39:15 +03:00
k_HandleHorizontalLineBreakingMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
#endregion
// Special handling of characters that are not ignored at the end of a line.
if ( charCode = = 9 )
{
m_textInfo . characterInfo [ m_characterCount ] . isVisible = false ;
m_lastVisibleCharacterOfLine = m_characterCount ;
m_textInfo . lineInfo [ m_lineNumber ] . spaceCount + = 1 ;
m_textInfo . spaceCount + = 1 ;
}
else if ( charCode = = 0xAD )
{
m_textInfo . characterInfo [ m_characterCount ] . isVisible = false ;
}
else
{
// Determine Vertex Color
if ( m_overrideHtmlColors )
vertexColor = m_fontColor32 ;
else
vertexColor = m_htmlColor ;
2022-01-12 10:39:15 +03:00
k_SaveGlyphVertexDataMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Store Character & Sprite Vertex Information
if ( m_textElementType = = TMP_TextElementType . Character )
{
// Save Character Vertex Data
SaveGlyphVertexInfo ( padding , style_padding , vertexColor ) ;
}
else if ( m_textElementType = = TMP_TextElementType . Sprite )
{
SaveSpriteVertexInfo ( vertexColor ) ;
}
2022-01-12 10:39:15 +03:00
k_SaveGlyphVertexDataMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
if ( isStartOfNewLine )
{
isStartOfNewLine = false ;
m_firstVisibleCharacterOfLine = m_characterCount ;
}
m_lineVisibleCharacterCount + = 1 ;
m_lastVisibleCharacterOfLine = m_characterCount ;
m_textInfo . lineInfo [ m_lineNumber ] . marginLeft = marginLeft ;
m_textInfo . lineInfo [ m_lineNumber ] . marginRight = marginRight ;
}
2022-01-12 10:39:15 +03:00
k_HandleVisibleCharacterMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
else
{
2022-01-12 10:39:15 +03:00
k_HandleWhiteSpacesMarker . Begin ( ) ;
// Special handling for text overflow linked mode
#region Check Vertical Bounds
if ( m_overflowMode = = TextOverflowModes . Linked & & ( charCode = = 10 | | charCode = = 11 ) )
{
float textHeight = m_maxTextAscender - ( m_maxLineDescender - m_lineOffset ) + ( m_lineOffset > 0 & & m_IsDrivenLineSpacing = = false ? m_maxLineAscender - m_startOfLineAscender : 0 ) ;
int testedCharacterCount = m_characterCount ;
if ( textHeight > marginHeight + 0.0001f )
{
// Set isTextOverflowing and firstOverflowCharacterIndex
if ( m_firstOverflowCharacterIndex = = - 1 )
m_firstOverflowCharacterIndex = m_characterCount ;
i = RestoreWordWrappingState ( ref m_SavedLastValidState ) ;
if ( m_linkedTextComponent ! = null )
{
m_linkedTextComponent . text = text ;
m_linkedTextComponent . m_inputSource = m_inputSource ;
m_linkedTextComponent . firstVisibleCharacter = m_characterCount ;
m_linkedTextComponent . ForceMeshUpdate ( ) ;
m_isTextTruncated = true ;
}
// Truncate remaining text
characterToSubstitute . index = testedCharacterCount ;
characterToSubstitute . unicode = 0x03 ;
k_HandleWhiteSpacesMarker . End ( ) ;
continue ;
}
}
#endregion
2022-01-12 10:06:03 +03:00
// Track # of spaces per line which is used for line justification.
if ( ( charCode = = 10 | | charCode = = 11 | | charCode = = 0xA0 | | charCode = = 0x2007 | | charCode = = 0x2028 | | charCode = = 0x2029 | | char . IsSeparator ( ( char ) charCode ) ) & & charCode ! = 0xAD & & charCode ! = 0x200B & & charCode ! = 0x2060 )
{
m_textInfo . lineInfo [ m_lineNumber ] . spaceCount + = 1 ;
m_textInfo . spaceCount + = 1 ;
}
if ( charCode = = 0xA0 )
m_textInfo . lineInfo [ m_lineNumber ] . controlCharacterCount + = 1 ;
2022-01-12 10:39:15 +03:00
k_HandleWhiteSpacesMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
#endregion Handle Visible Characters
// Tracking of potential insertion positions for Ellipsis character
#region Track Potential Insertion Location for Ellipsis
if ( m_overflowMode = = TextOverflowModes . Ellipsis & & ( isInjectingCharacter = = false | | charCode = = 0x2D ) )
{
float fontScale = m_currentFontSize / m_Ellipsis . fontAsset . m_FaceInfo . pointSize * m_Ellipsis . fontAsset . m_FaceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ;
float scale = fontScale * m_fontScaleMultiplier * m_Ellipsis . character . m_Scale * m_Ellipsis . character . m_Glyph . scale ;
float marginLeft = m_marginLeft ;
float marginRight = m_marginRight ;
// Use the scale and margins of the previous character if Line Feed (LF) is not the first character of a line.
if ( charCode = = 0x0A & & m_characterCount ! = m_firstCharacterOfLine )
{
fontScale = m_textInfo . characterInfo [ m_characterCount - 1 ] . pointSize / m_Ellipsis . fontAsset . m_FaceInfo . pointSize * m_Ellipsis . fontAsset . m_FaceInfo . scale * ( m_isOrthographic ? 1 : 0.1f ) ;
scale = fontScale * m_fontScaleMultiplier * m_Ellipsis . character . m_Scale * m_Ellipsis . character . m_Glyph . scale ;
marginLeft = m_textInfo . lineInfo [ m_lineNumber ] . marginLeft ;
marginRight = m_textInfo . lineInfo [ m_lineNumber ] . marginRight ;
}
float textHeight = m_maxTextAscender - ( m_maxLineDescender - m_lineOffset ) + ( m_lineOffset > 0 & & m_IsDrivenLineSpacing = = false ? m_maxLineAscender - m_startOfLineAscender : 0 ) ;
float textWidth = Mathf . Abs ( m_xAdvance ) + ( ! m_isRightToLeft ? m_Ellipsis . character . m_Glyph . metrics . horizontalAdvance : 0 ) * ( 1 - m_charWidthAdjDelta ) * scale ;
float widthOfTextAreaForEllipsis = m_width ! = - 1 ? Mathf . Min ( marginWidth + 0.0001f - marginLeft - marginRight , m_width ) : marginWidth + 0.0001f - marginLeft - marginRight ;
if ( textWidth < widthOfTextAreaForEllipsis * ( isJustifiedOrFlush ? 1.05f : 1.0f ) & & textHeight < marginHeight + 0.0001f )
{
SaveWordWrappingState ( ref m_SavedEllipsisState , i , m_characterCount ) ;
m_EllipsisInsertionCandidateStack . Push ( m_SavedEllipsisState ) ;
}
}
#endregion
// Store Rectangle positions for each Character.
#region Store Character Data
m_textInfo . characterInfo [ m_characterCount ] . lineNumber = m_lineNumber ;
m_textInfo . characterInfo [ m_characterCount ] . pageNumber = m_pageNumber ;
if ( charCode ! = 10 & & charCode ! = 11 & & charCode ! = 13 & & isInjectingCharacter = = false /* && charCode != 8230 */ | | m_textInfo . lineInfo [ m_lineNumber ] . characterCount = = 1 )
m_textInfo . lineInfo [ m_lineNumber ] . alignment = m_lineJustification ;
#endregion Store Character Data
// Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
#region XAdvance , Tabulation & Stops
2022-01-12 10:39:15 +03:00
k_ComputeCharacterAdvanceMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
if ( charCode = = 9 )
{
float tabSize = m_currentFontAsset . m_FaceInfo . tabWidth * m_currentFontAsset . tabSize * currentElementScale ;
float tabs = Mathf . Ceil ( m_xAdvance / tabSize ) * tabSize ;
m_xAdvance = tabs > m_xAdvance ? tabs : m_xAdvance + tabSize ;
}
else if ( m_monoSpacing ! = 0 )
{
m_xAdvance + = ( m_monoSpacing - monoAdvance + ( ( m_currentFontAsset . normalSpacingOffset + characterSpacingAdjustment ) * currentEmScale ) + m_cSpacing ) * ( 1 - m_charWidthAdjDelta ) ;
if ( isWhiteSpace | | charCode = = 0x200B )
m_xAdvance + = m_wordSpacing * currentEmScale ;
}
else if ( m_isRightToLeft )
{
2022-01-12 10:39:15 +03:00
m_xAdvance - = ( ( glyphAdjustments . m_XAdvance * currentElementScale + ( m_currentFontAsset . normalSpacingOffset + characterSpacingAdjustment + boldSpacingAdjustment ) * currentEmScale + m_cSpacing ) * ( 1 - m_charWidthAdjDelta ) ) ;
2022-01-12 10:06:03 +03:00
if ( isWhiteSpace | | charCode = = 0x200B )
m_xAdvance - = m_wordSpacing * currentEmScale ;
}
else
{
float scaleFXMultiplier = 1 ;
if ( m_isFXMatrixSet ) scaleFXMultiplier = m_FXMatrix . lossyScale . x ;
2022-01-12 10:39:15 +03:00
m_xAdvance + = ( ( currentGlyphMetrics . horizontalAdvance * scaleFXMultiplier + glyphAdjustments . m_XAdvance ) * currentElementScale + ( m_currentFontAsset . normalSpacingOffset + characterSpacingAdjustment + boldSpacingAdjustment ) * currentEmScale + m_cSpacing ) * ( 1 - m_charWidthAdjDelta ) ;
2022-01-12 10:06:03 +03:00
if ( isWhiteSpace | | charCode = = 0x200B )
m_xAdvance + = m_wordSpacing * currentEmScale ;
}
// Store xAdvance information
m_textInfo . characterInfo [ m_characterCount ] . xAdvance = m_xAdvance ;
2022-01-12 10:39:15 +03:00
k_ComputeCharacterAdvanceMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
#endregion Tabulation & Stops
// Handle Carriage Return
#region Carriage Return
if ( charCode = = 13 )
{
2022-01-12 10:39:15 +03:00
k_HandleCarriageReturnMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
m_xAdvance = 0 + tag_Indent ;
2022-01-12 10:39:15 +03:00
k_HandleCarriageReturnMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
#endregion Carriage Return
// Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
#region Check for Line Feed and Last Character
if ( charCode = = 10 | | charCode = = 11 | | charCode = = 0x03 | | charCode = = 0x2028 | | charCode = = 0x2029 | | ( charCode = = 0x2D & & isInjectingCharacter ) | | m_characterCount = = totalCharacterCount - 1 )
{
2022-01-12 10:39:15 +03:00
k_HandleLineTerminationMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Adjust current line spacing (if necessary) before inserting new line
float baselineAdjustmentDelta = m_maxLineAscender - m_startOfLineAscender ;
if ( m_lineOffset > 0 & & Math . Abs ( baselineAdjustmentDelta ) > 0.01f & & m_IsDrivenLineSpacing = = false & & ! m_isNewPage )
{
//Debug.Log("Line Feed - Adjusting Line Spacing on line #" + m_lineNumber);
AdjustLineOffset ( m_firstCharacterOfLine , m_characterCount , baselineAdjustmentDelta ) ;
m_ElementDescender - = baselineAdjustmentDelta ;
m_lineOffset + = baselineAdjustmentDelta ;
// Adjust saved ellipsis state only if we are adjusting the same line number
if ( m_SavedEllipsisState . lineNumber = = m_lineNumber )
{
m_SavedEllipsisState = m_EllipsisInsertionCandidateStack . Pop ( ) ;
m_SavedEllipsisState . startOfLineAscender + = baselineAdjustmentDelta ;
m_SavedEllipsisState . lineOffset + = baselineAdjustmentDelta ;
m_EllipsisInsertionCandidateStack . Push ( m_SavedEllipsisState ) ;
}
}
m_isNewPage = false ;
// Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
float lineAscender = m_maxLineAscender - m_lineOffset ;
float lineDescender = m_maxLineDescender - m_lineOffset ;
// Update maxDescender and maxVisibleDescender
m_ElementDescender = m_ElementDescender < lineDescender ? m_ElementDescender : lineDescender ;
if ( ! isMaxVisibleDescenderSet )
maxVisibleDescender = m_ElementDescender ;
if ( m_useMaxVisibleDescender & & ( m_characterCount > = m_maxVisibleCharacters | | m_lineNumber > = m_maxVisibleLines ) )
isMaxVisibleDescenderSet = true ;
// Save Line Information
m_textInfo . lineInfo [ m_lineNumber ] . firstCharacterIndex = m_firstCharacterOfLine ;
m_textInfo . lineInfo [ m_lineNumber ] . firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine = m_firstCharacterOfLine > m_firstVisibleCharacterOfLine ? m_firstCharacterOfLine : m_firstVisibleCharacterOfLine ;
m_textInfo . lineInfo [ m_lineNumber ] . lastCharacterIndex = m_lastCharacterOfLine = m_characterCount ;
m_textInfo . lineInfo [ m_lineNumber ] . lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine = m_lastVisibleCharacterOfLine < m_firstVisibleCharacterOfLine ? m_firstVisibleCharacterOfLine : m_lastVisibleCharacterOfLine ;
m_textInfo . lineInfo [ m_lineNumber ] . characterCount = m_textInfo . lineInfo [ m_lineNumber ] . lastCharacterIndex - m_textInfo . lineInfo [ m_lineNumber ] . firstCharacterIndex + 1 ;
m_textInfo . lineInfo [ m_lineNumber ] . visibleCharacterCount = m_lineVisibleCharacterCount ;
m_textInfo . lineInfo [ m_lineNumber ] . lineExtents . min = new Vector2 ( m_textInfo . characterInfo [ m_firstVisibleCharacterOfLine ] . bottomLeft . x , lineDescender ) ;
m_textInfo . lineInfo [ m_lineNumber ] . lineExtents . max = new Vector2 ( m_textInfo . characterInfo [ m_lastVisibleCharacterOfLine ] . topRight . x , lineAscender ) ;
m_textInfo . lineInfo [ m_lineNumber ] . length = m_textInfo . lineInfo [ m_lineNumber ] . lineExtents . max . x - ( padding * currentElementScale ) ;
m_textInfo . lineInfo [ m_lineNumber ] . width = widthOfTextArea ;
if ( m_textInfo . lineInfo [ m_lineNumber ] . characterCount = = 1 )
m_textInfo . lineInfo [ m_lineNumber ] . alignment = m_lineJustification ;
2022-01-12 10:39:15 +03:00
float maxAdvanceOffset = ( ( m_currentFontAsset . normalSpacingOffset + characterSpacingAdjustment + boldSpacingAdjustment ) * currentEmScale - m_cSpacing ) * ( 1 - m_charWidthAdjDelta ) ;
2022-01-12 10:06:03 +03:00
if ( m_textInfo . characterInfo [ m_lastVisibleCharacterOfLine ] . isVisible )
m_textInfo . lineInfo [ m_lineNumber ] . maxAdvance = m_textInfo . characterInfo [ m_lastVisibleCharacterOfLine ] . xAdvance + ( m_isRightToLeft ? maxAdvanceOffset : - maxAdvanceOffset ) ;
else
m_textInfo . lineInfo [ m_lineNumber ] . maxAdvance = m_textInfo . characterInfo [ m_lastCharacterOfLine ] . xAdvance + ( m_isRightToLeft ? maxAdvanceOffset : - maxAdvanceOffset ) ;
m_textInfo . lineInfo [ m_lineNumber ] . baseline = 0 - m_lineOffset ;
m_textInfo . lineInfo [ m_lineNumber ] . ascender = lineAscender ;
m_textInfo . lineInfo [ m_lineNumber ] . descender = lineDescender ;
m_textInfo . lineInfo [ m_lineNumber ] . lineHeight = lineAscender - lineDescender + lineGap * baseScale ;
// Add new line if not last line or character.
if ( charCode = = 10 | | charCode = = 11 | | charCode = = 0x2D | | charCode = = 0x2028 | | charCode = = 0x2029 )
{
// Store the state of the line before starting on the new line.
SaveWordWrappingState ( ref m_SavedLineState , i , m_characterCount ) ;
m_lineNumber + = 1 ;
isStartOfNewLine = true ;
ignoreNonBreakingSpace = false ;
isFirstWordOfLine = true ;
m_firstCharacterOfLine = m_characterCount + 1 ;
m_lineVisibleCharacterCount = 0 ;
// Check to make sure Array is large enough to hold a new line.
if ( m_lineNumber > = m_textInfo . lineInfo . Length )
ResizeLineExtents ( m_lineNumber ) ;
float lastVisibleAscender = m_textInfo . characterInfo [ m_characterCount ] . adjustedAscender ;
// Apply Line Spacing with special handling for VT char(11)
if ( m_lineHeight = = TMP_Math . FLOAT_UNSET )
{
float lineOffsetDelta = 0 - m_maxLineDescender + lastVisibleAscender + ( lineGap + m_lineSpacingDelta ) * baseScale + ( m_lineSpacing + ( charCode = = 10 | | charCode = = 0x2029 ? m_paragraphSpacing : 0 ) ) * currentEmScale ;
m_lineOffset + = lineOffsetDelta ;
m_IsDrivenLineSpacing = false ;
}
else
{
m_lineOffset + = m_lineHeight + ( m_lineSpacing + ( charCode = = 10 | | charCode = = 0x2029 ? m_paragraphSpacing : 0 ) ) * currentEmScale ;
m_IsDrivenLineSpacing = true ;
}
m_maxLineAscender = k_LargeNegativeFloat ;
m_maxLineDescender = k_LargePositiveFloat ;
m_startOfLineAscender = lastVisibleAscender ;
m_xAdvance = 0 + tag_LineIndent + tag_Indent ;
SaveWordWrappingState ( ref m_SavedWordWrapState , i , m_characterCount ) ;
SaveWordWrappingState ( ref m_SavedLastValidState , i , m_characterCount ) ;
m_characterCount + = 1 ;
2022-01-12 10:39:15 +03:00
k_HandleLineTerminationMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
continue ;
}
// If End of Text
if ( charCode = = 0x03 )
2022-01-12 10:39:15 +03:00
i = m_TextProcessingArray . Length ;
2022-01-12 10:06:03 +03:00
2022-01-12 10:39:15 +03:00
k_HandleLineTerminationMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
#endregion Check for Linefeed or Last Character
// Store Rectangle positions for each Character.
#region Save CharacterInfo for the current character .
2022-01-12 10:39:15 +03:00
k_SavePageInfoMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
// Determine the bounds of the Mesh.
if ( m_textInfo . characterInfo [ m_characterCount ] . isVisible )
{
m_meshExtents . min . x = Mathf . Min ( m_meshExtents . min . x , m_textInfo . characterInfo [ m_characterCount ] . bottomLeft . x ) ;
m_meshExtents . min . y = Mathf . Min ( m_meshExtents . min . y , m_textInfo . characterInfo [ m_characterCount ] . bottomLeft . y ) ;
m_meshExtents . max . x = Mathf . Max ( m_meshExtents . max . x , m_textInfo . characterInfo [ m_characterCount ] . topRight . x ) ;
m_meshExtents . max . y = Mathf . Max ( m_meshExtents . max . y , m_textInfo . characterInfo [ m_characterCount ] . topRight . y ) ;
//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));
//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));
}
// Save pageInfo Data
if ( m_overflowMode = = TextOverflowModes . Page & & charCode ! = 10 & & charCode ! = 11 & & charCode ! = 13 & & charCode ! = 0x2028 & & charCode ! = 0x2029 ) // && m_pageNumber < 16)
{
// Check if we need to increase allocations for the pageInfo array.
if ( m_pageNumber + 1 > m_textInfo . pageInfo . Length )
TMP_TextInfo . Resize ( ref m_textInfo . pageInfo , m_pageNumber + 1 , true ) ;
m_textInfo . pageInfo [ m_pageNumber ] . ascender = m_PageAscender ;
m_textInfo . pageInfo [ m_pageNumber ] . descender = m_ElementDescender < m_textInfo . pageInfo [ m_pageNumber ] . descender
? m_ElementDescender
: m_textInfo . pageInfo [ m_pageNumber ] . descender ;
if ( m_pageNumber = = 0 & & m_characterCount = = 0 )
m_textInfo . pageInfo [ m_pageNumber ] . firstCharacterIndex = m_characterCount ;
else if ( m_characterCount > 0 & & m_pageNumber ! = m_textInfo . characterInfo [ m_characterCount - 1 ] . pageNumber )
{
m_textInfo . pageInfo [ m_pageNumber - 1 ] . lastCharacterIndex = m_characterCount - 1 ;
m_textInfo . pageInfo [ m_pageNumber ] . firstCharacterIndex = m_characterCount ;
}
else if ( m_characterCount = = totalCharacterCount - 1 )
m_textInfo . pageInfo [ m_pageNumber ] . lastCharacterIndex = m_characterCount ;
}
2022-01-12 10:39:15 +03:00
k_SavePageInfoMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
#endregion Saving CharacterInfo
// Save State of Mesh Creation for handling of Word Wrapping
#region Save Word Wrapping State
if ( m_enableWordWrapping | | m_overflowMode = = TextOverflowModes . Truncate | | m_overflowMode = = TextOverflowModes . Ellipsis | | m_overflowMode = = TextOverflowModes . Linked )
{
2022-01-12 10:39:15 +03:00
k_SaveProcessingStatesMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
if ( ( isWhiteSpace | | charCode = = 0x200B | | charCode = = 0x2D | | charCode = = 0xAD ) & & ( ! m_isNonBreakingSpace | | ignoreNonBreakingSpace ) & & charCode ! = 0xA0 & & charCode ! = 0x2007 & & charCode ! = 0x2011 & & charCode ! = 0x202F & & charCode ! = 0x2060 )
{
// We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored
// for Word Wrapping.
SaveWordWrappingState ( ref m_SavedWordWrapState , i , m_characterCount ) ;
isFirstWordOfLine = false ;
//isLastCharacterCJK = false;
// Reset soft line breaking point since we now have a valid hard break point.
m_SavedSoftLineBreakState . previous_WordBreak = - 1 ;
}
// Handling for East Asian characters
else if ( m_isNonBreakingSpace = = false & &
( ( charCode > 0x1100 & & charCode < 0x11ff | | /* Hangul Jamo */
charCode > 0xA960 & & charCode < 0xA97F | | /* Hangul Jamo Extended-A */
charCode > 0xAC00 & & charCode < 0xD7FF ) & & /* Hangul Syllables */
TMP_Settings . useModernHangulLineBreakingRules = = false | |
( charCode > 0x2E80 & & charCode < 0x9FFF | | /* CJK */
charCode > 0xF900 & & charCode < 0xFAFF | | /* CJK Compatibility Ideographs */
charCode > 0xFE30 & & charCode < 0xFE4F | | /* CJK Compatibility Forms */
charCode > 0xFF00 & & charCode < 0xFFEF ) ) ) /* CJK Halfwidth */
{
bool isCurrentLeadingCharacter = TMP_Settings . linebreakingRules . leadingCharacters . ContainsKey ( charCode ) ;
bool isNextFollowingCharacter = m_characterCount < totalCharacterCount - 1 & & TMP_Settings . linebreakingRules . followingCharacters . ContainsKey ( m_textInfo . characterInfo [ m_characterCount + 1 ] . character ) ;
if ( isCurrentLeadingCharacter = = false )
{
if ( isNextFollowingCharacter = = false )
{
SaveWordWrappingState ( ref m_SavedWordWrapState , i , m_characterCount ) ;
isFirstWordOfLine = false ;
}
if ( isFirstWordOfLine )
{
// Special handling for non-breaking space and soft line breaks
if ( isWhiteSpace )
SaveWordWrappingState ( ref m_SavedSoftLineBreakState , i , m_characterCount ) ;
SaveWordWrappingState ( ref m_SavedWordWrapState , i , m_characterCount ) ;
}
}
else
{
if ( isFirstWordOfLine & & isFirstCharacterOfLine )
{
// Special handling for non-breaking space and soft line breaks
if ( isWhiteSpace )
SaveWordWrappingState ( ref m_SavedSoftLineBreakState , i , m_characterCount ) ;
SaveWordWrappingState ( ref m_SavedWordWrapState , i , m_characterCount ) ;
}
}
//isLastCharacterCJK = true;
}
else if ( isFirstWordOfLine )
{
// Special handling for non-breaking space and soft line breaks
if ( isWhiteSpace | | ( charCode = = 0xAD & & isSoftHyphenIgnored = = false ) )
SaveWordWrappingState ( ref m_SavedSoftLineBreakState , i , m_characterCount ) ;
SaveWordWrappingState ( ref m_SavedWordWrapState , i , m_characterCount ) ;
//isLastCharacterCJK = false;
}
2022-01-12 10:39:15 +03:00
k_SaveProcessingStatesMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
#endregion Save Word Wrapping State
SaveWordWrappingState ( ref m_SavedLastValidState , i , m_characterCount ) ;
m_characterCount + = 1 ;
}
// Check Auto Sizing and increase font size to fill text container.
#region Check Auto - Sizing ( Upper Font Size Bounds )
fontSizeDelta = m_maxFontSize - m_minFontSize ;
if ( /* !m_isCharacterWrappingEnabled && */ m_enableAutoSizing & & fontSizeDelta > 0.051f & & m_fontSize < m_fontSizeMax & & m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount )
{
// Reset character width adjustment delta
if ( m_charWidthAdjDelta < m_charWidthMaxAdj / 100 )
m_charWidthAdjDelta = 0 ;
m_minFontSize = m_fontSize ;
float sizeDelta = Mathf . Max ( ( m_maxFontSize - m_fontSize ) / 2 , 0.05f ) ;
m_fontSize + = sizeDelta ;
m_fontSize = Mathf . Min ( ( int ) ( m_fontSize * 20 + 0.5f ) / 20f , m_fontSizeMax ) ;
//Debug.Log("[" + m_AutoSizeIterationCount + "] Increasing Point Size from [" + m_minFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
2022-01-12 10:39:15 +03:00
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
#endregion End Auto - sizing Check
m_IsAutoSizePointSizeSet = true ;
if ( m_AutoSizeIterationCount > = m_AutoSizeMaxIterationCount )
Debug . Log ( "Auto Size Iteration Count: " + m_AutoSizeIterationCount + ". Final Point Size: " + m_fontSize ) ;
// If there are no visible characters or only character is End of Text (0x03)... no need to continue
if ( m_characterCount = = 0 | | ( m_characterCount = = 1 & & charCode = = 0x03 ) )
{
ClearMesh ( true ) ;
// Event indicating the text has been regenerated.
TMPro_EventManager . ON_TEXT_CHANGED ( this ) ;
2022-01-12 10:39:15 +03:00
k_GenerateTextPhaseIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
return ;
}
// End Sampling of Phase I
2022-01-12 10:39:15 +03:00
k_GenerateTextPhaseIMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
// *** PHASE II of Text Generation ***
2022-01-12 10:39:15 +03:00
k_GenerateTextPhaseIIMarker . Begin ( ) ;
int last_vert_index = m_materialReferences [ m_Underline . materialIndex ] . referenceCount * 4 ;
2022-01-12 10:06:03 +03:00
// Partial clear of the vertices array to mark unused vertices as degenerate.
m_textInfo . meshInfo [ 0 ] . Clear ( false ) ;
// Handle Text Alignment
#region Text Vertical Alignment
Vector3 anchorOffset = Vector3 . zero ;
Vector3 [ ] corners = m_RectTransformCorners ; // GetTextContainerLocalCorners();
// Handle Vertical Text Alignment
switch ( m_VerticalAlignment )
{
// Top Vertically
case VerticalAlignmentOptions . Top :
if ( m_overflowMode ! = TextOverflowModes . Page )
anchorOffset = corners [ 1 ] + new Vector3 ( 0 + margins . x , 0 - m_maxTextAscender - margins . y , 0 ) ;
else
anchorOffset = corners [ 1 ] + new Vector3 ( 0 + margins . x , 0 - m_textInfo . pageInfo [ pageToDisplay ] . ascender - margins . y , 0 ) ;
break ;
// Middle Vertically
case VerticalAlignmentOptions . Middle :
if ( m_overflowMode ! = TextOverflowModes . Page )
anchorOffset = ( corners [ 0 ] + corners [ 1 ] ) / 2 + new Vector3 ( 0 + margins . x , 0 - ( m_maxTextAscender + margins . y + maxVisibleDescender - margins . w ) / 2 , 0 ) ;
else
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 ) ;
break ;
// Bottom Vertically
case VerticalAlignmentOptions . Bottom :
if ( m_overflowMode ! = TextOverflowModes . Page )
anchorOffset = corners [ 0 ] + new Vector3 ( 0 + margins . x , 0 - maxVisibleDescender + margins . w , 0 ) ;
else
anchorOffset = corners [ 0 ] + new Vector3 ( 0 + margins . x , 0 - m_textInfo . pageInfo [ pageToDisplay ] . descender + margins . w , 0 ) ;
break ;
// Baseline Vertically
case VerticalAlignmentOptions . Baseline :
anchorOffset = ( corners [ 0 ] + corners [ 1 ] ) / 2 + new Vector3 ( 0 + margins . x , 0 , 0 ) ;
break ;
// Midline Vertically
case VerticalAlignmentOptions . Geometry :
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 ) ;
break ;
// Capline Vertically
case VerticalAlignmentOptions . Capline :
anchorOffset = ( corners [ 0 ] + corners [ 1 ] ) / 2 + new Vector3 ( 0 + margins . x , 0 - ( m_maxCapHeight - margins . y - margins . w ) / 2 , 0 ) ;
break ;
}
#endregion
// Initialization for Second Pass
Vector3 justificationOffset = Vector3 . zero ;
Vector3 offset = Vector3 . zero ;
int vert_index_X4 = 0 ;
int sprite_index_X4 = 0 ;
int wordCount = 0 ;
int lineCount = 0 ;
int lastLine = 0 ;
bool isFirstSeperator = false ;
bool isStartOfWord = false ;
int wordFirstChar = 0 ;
int wordLastChar = 0 ;
// Second Pass : Line Justification, UV Mapping, Character & Line Visibility & more.
float lossyScale = m_previousLossyScaleY = this . transform . lossyScale . y ;
Color32 underlineColor = Color . white ;
Color32 strikethroughColor = Color . white ;
HighlightState highlightState = new HighlightState ( new Color32 ( 255 , 255 , 0 , 64 ) , TMP_Offset . zero ) ;
float xScale = 0 ;
float xScaleMax = 0 ;
float underlineStartScale = 0 ;
float underlineEndScale = 0 ;
float underlineMaxScale = 0 ;
float underlineBaseLine = k_LargePositiveFloat ;
int lastPage = 0 ;
float strikethroughPointSize = 0 ;
float strikethroughScale = 0 ;
float strikethroughBaseline = 0 ;
TMP_CharacterInfo [ ] characterInfos = m_textInfo . characterInfo ;
#region Handle Line Justification & UV Mapping & Character Visibility & More
for ( int i = 0 ; i < m_characterCount ; i + + )
{
TMP_FontAsset currentFontAsset = characterInfos [ i ] . fontAsset ;
char unicode = characterInfos [ i ] . character ;
int currentLine = characterInfos [ i ] . lineNumber ;
TMP_LineInfo lineInfo = m_textInfo . lineInfo [ currentLine ] ;
lineCount = currentLine + 1 ;
HorizontalAlignmentOptions lineAlignment = lineInfo . alignment ;
// Process Line Justification
#region Handle Line Justification
switch ( lineAlignment )
{
case HorizontalAlignmentOptions . Left :
if ( ! m_isRightToLeft )
justificationOffset = new Vector3 ( 0 + lineInfo . marginLeft , 0 , 0 ) ;
else
justificationOffset = new Vector3 ( 0 - lineInfo . maxAdvance , 0 , 0 ) ;
break ;
case HorizontalAlignmentOptions . Center :
justificationOffset = new Vector3 ( lineInfo . marginLeft + lineInfo . width / 2 - lineInfo . maxAdvance / 2 , 0 , 0 ) ;
break ;
case HorizontalAlignmentOptions . Geometry :
justificationOffset = new Vector3 ( lineInfo . marginLeft + lineInfo . width / 2 - ( lineInfo . lineExtents . min . x + lineInfo . lineExtents . max . x ) / 2 , 0 , 0 ) ;
break ;
case HorizontalAlignmentOptions . Right :
if ( ! m_isRightToLeft )
justificationOffset = new Vector3 ( lineInfo . marginLeft + lineInfo . width - lineInfo . maxAdvance , 0 , 0 ) ;
else
justificationOffset = new Vector3 ( lineInfo . marginLeft + lineInfo . width , 0 , 0 ) ;
break ;
case HorizontalAlignmentOptions . Justified :
case HorizontalAlignmentOptions . Flush :
// Skip Zero Width Characters
if ( unicode = = 0x0A | | unicode = = 0xAD | | unicode = = 0x200B | | unicode = = 0x2060 | | unicode = = 0x03 ) break ;
char lastCharOfCurrentLine = characterInfos [ lineInfo . lastCharacterIndex ] . character ;
2022-01-12 10:39:15 +03:00
2022-01-12 10:06:03 +03:00
bool isFlush = ( lineAlignment & HorizontalAlignmentOptions . Flush ) = = HorizontalAlignmentOptions . Flush ;
// In Justified mode, all lines are justified except the last one.
// In Flush mode, all lines are justified.
if ( char . IsControl ( lastCharOfCurrentLine ) = = false & & currentLine < m_lineNumber | | isFlush | | lineInfo . maxAdvance > lineInfo . width )
{
// First character of each line.
2022-01-12 10:39:15 +03:00
if ( currentLine ! = lastLine | | i = = 0 | | i = = m_firstVisibleCharacter )
2022-01-12 10:06:03 +03:00
{
if ( ! m_isRightToLeft )
justificationOffset = new Vector3 ( lineInfo . marginLeft , 0 , 0 ) ;
else
justificationOffset = new Vector3 ( lineInfo . marginLeft + lineInfo . width , 0 , 0 ) ;
if ( char . IsSeparator ( unicode ) )
isFirstSeperator = true ;
else
isFirstSeperator = false ;
}
else
{
float gap = ! m_isRightToLeft ? lineInfo . width - lineInfo . maxAdvance : lineInfo . width + lineInfo . maxAdvance ;
int visibleCount = lineInfo . visibleCharacterCount - 1 + lineInfo . controlCharacterCount ;
// Get the number of spaces for each line ignoring the last character if it is not visible (ie. a space or linefeed).
int spaces = ( characterInfos [ lineInfo . lastCharacterIndex ] . isVisible ? lineInfo . spaceCount : lineInfo . spaceCount - 1 ) - lineInfo . controlCharacterCount ;
if ( isFirstSeperator ) { spaces - = 1 ; visibleCount + = 1 ; }
float ratio = spaces > 0 ? m_wordWrappingRatios : 1 ;
if ( spaces < 1 ) spaces = 1 ;
if ( unicode ! = 0xA0 & & ( unicode = = 9 | | char . IsSeparator ( ( char ) unicode ) ) )
{
if ( ! m_isRightToLeft )
justificationOffset + = new Vector3 ( gap * ( 1 - ratio ) / spaces , 0 , 0 ) ;
else
justificationOffset - = new Vector3 ( gap * ( 1 - ratio ) / spaces , 0 , 0 ) ;
}
else
{
if ( ! m_isRightToLeft )
justificationOffset + = new Vector3 ( gap * ratio / visibleCount , 0 , 0 ) ;
else
justificationOffset - = new Vector3 ( gap * ratio / visibleCount , 0 , 0 ) ;
}
}
}
else
{
if ( ! m_isRightToLeft )
justificationOffset = new Vector3 ( lineInfo . marginLeft , 0 , 0 ) ; // Keep last line left justified.
else
justificationOffset = new Vector3 ( lineInfo . marginLeft + lineInfo . width , 0 , 0 ) ; // Keep last line right justified.
}
//Debug.Log("Char [" + (char)charCode + "] Code:" + charCode + " Line # " + currentLine + " Offset:" + justificationOffset + " # Spaces:" + lineInfo.spaceCount + " # Characters:" + lineInfo.characterCount);
break ;
}
#endregion End Text Justification
offset = anchorOffset + justificationOffset ;
// Handle UV2 mapping options and packing of scale information into UV2.
#region Handling of UV2 mapping & Scale packing
bool isCharacterVisible = characterInfos [ i ] . isVisible ;
if ( isCharacterVisible )
{
TMP_TextElementType elementType = characterInfos [ i ] . elementType ;
switch ( elementType )
{
// CHARACTERS
case TMP_TextElementType . Character :
Extents lineExtents = lineInfo . lineExtents ;
float uvOffset = ( m_uvLineOffset * currentLine ) % 1 ; // + m_uvOffset.x;
// Setup UV2 based on Character Mapping Options Selected
#region Handle UV Mapping Options
switch ( m_horizontalMapping )
{
case TextureMappingOptions . Character :
characterInfos [ i ] . vertex_BL . uv2 . x = 0 ; //+ m_uvOffset.x;
characterInfos [ i ] . vertex_TL . uv2 . x = 0 ; //+ m_uvOffset.x;
characterInfos [ i ] . vertex_TR . uv2 . x = 1 ; //+ m_uvOffset.x;
characterInfos [ i ] . vertex_BR . uv2 . x = 1 ; //+ m_uvOffset.x;
break ;
case TextureMappingOptions . Line :
if ( m_textAlignment ! = TextAlignmentOptions . Justified )
{
characterInfos [ i ] . vertex_BL . uv2 . x = ( characterInfos [ i ] . vertex_BL . position . x - lineExtents . min . x ) / ( lineExtents . max . x - lineExtents . min . x ) + uvOffset ;
characterInfos [ i ] . vertex_TL . uv2 . x = ( characterInfos [ i ] . vertex_TL . position . x - lineExtents . min . x ) / ( lineExtents . max . x - lineExtents . min . x ) + uvOffset ;
characterInfos [ i ] . vertex_TR . uv2 . x = ( characterInfos [ i ] . vertex_TR . position . x - lineExtents . min . x ) / ( lineExtents . max . x - lineExtents . min . x ) + uvOffset ;
characterInfos [ i ] . vertex_BR . uv2 . x = ( characterInfos [ i ] . vertex_BR . position . x - lineExtents . min . x ) / ( lineExtents . max . x - lineExtents . min . x ) + uvOffset ;
break ;
}
else // Special Case if Justified is used in Line Mode.
{
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 ;
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 ;
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 ;
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 ;
break ;
}
case TextureMappingOptions . Paragraph :
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 ;
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 ;
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 ;
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 ;
break ;
case TextureMappingOptions . MatchAspect :
switch ( m_verticalMapping )
{
case TextureMappingOptions . Character :
characterInfos [ i ] . vertex_BL . uv2 . y = 0 ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_TL . uv2 . y = 1 ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_TR . uv2 . y = 0 ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_BR . uv2 . y = 1 ; // + m_uvOffset.y;
break ;
case TextureMappingOptions . Line :
characterInfos [ i ] . vertex_BL . uv2 . y = ( characterInfos [ i ] . vertex_BL . position . y - lineExtents . min . y ) / ( lineExtents . max . y - lineExtents . min . y ) + uvOffset ;
characterInfos [ i ] . vertex_TL . uv2 . y = ( characterInfos [ i ] . vertex_TL . position . y - lineExtents . min . y ) / ( lineExtents . max . y - lineExtents . min . y ) + uvOffset ;
characterInfos [ i ] . vertex_TR . uv2 . y = characterInfos [ i ] . vertex_BL . uv2 . y ;
characterInfos [ i ] . vertex_BR . uv2 . y = characterInfos [ i ] . vertex_TL . uv2 . y ;
break ;
case TextureMappingOptions . Paragraph :
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 ;
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 ;
characterInfos [ i ] . vertex_TR . uv2 . y = characterInfos [ i ] . vertex_BL . uv2 . y ;
characterInfos [ i ] . vertex_BR . uv2 . y = characterInfos [ i ] . vertex_TL . uv2 . y ;
break ;
case TextureMappingOptions . MatchAspect :
Debug . Log ( "ERROR: Cannot Match both Vertical & Horizontal." ) ;
break ;
}
//float xDelta = 1 - (_uv2s[vert_index + 0].y * textMeshCharacterInfo[i].AspectRatio); // Left aligned
float xDelta = ( 1 - ( ( characterInfos [ i ] . vertex_BL . uv2 . y + characterInfos [ i ] . vertex_TL . uv2 . y ) * characterInfos [ i ] . aspectRatio ) ) / 2 ; // Center of Rectangle
characterInfos [ i ] . vertex_BL . uv2 . x = ( characterInfos [ i ] . vertex_BL . uv2 . y * characterInfos [ i ] . aspectRatio ) + xDelta + uvOffset ;
characterInfos [ i ] . vertex_TL . uv2 . x = characterInfos [ i ] . vertex_BL . uv2 . x ;
characterInfos [ i ] . vertex_TR . uv2 . x = ( characterInfos [ i ] . vertex_TL . uv2 . y * characterInfos [ i ] . aspectRatio ) + xDelta + uvOffset ;
characterInfos [ i ] . vertex_BR . uv2 . x = characterInfos [ i ] . vertex_TR . uv2 . x ;
break ;
}
switch ( m_verticalMapping )
{
case TextureMappingOptions . Character :
characterInfos [ i ] . vertex_BL . uv2 . y = 0 ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_TL . uv2 . y = 1 ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_TR . uv2 . y = 1 ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_BR . uv2 . y = 0 ; // + m_uvOffset.y;
break ;
case TextureMappingOptions . Line :
characterInfos [ i ] . vertex_BL . uv2 . y = ( characterInfos [ i ] . vertex_BL . position . y - lineInfo . descender ) / ( lineInfo . ascender - lineInfo . descender ) ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_TL . uv2 . y = ( characterInfos [ i ] . vertex_TL . position . y - lineInfo . descender ) / ( lineInfo . ascender - lineInfo . descender ) ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_TR . uv2 . y = characterInfos [ i ] . vertex_TL . uv2 . y ;
characterInfos [ i ] . vertex_BR . uv2 . y = characterInfos [ i ] . vertex_BL . uv2 . y ;
break ;
case TextureMappingOptions . Paragraph :
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;
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;
characterInfos [ i ] . vertex_TR . uv2 . y = characterInfos [ i ] . vertex_TL . uv2 . y ;
characterInfos [ i ] . vertex_BR . uv2 . y = characterInfos [ i ] . vertex_BL . uv2 . y ;
break ;
case TextureMappingOptions . MatchAspect :
float yDelta = ( 1 - ( ( characterInfos [ i ] . vertex_BL . uv2 . x + characterInfos [ i ] . vertex_TR . uv2 . x ) / characterInfos [ i ] . aspectRatio ) ) / 2 ; // Center of Rectangle
characterInfos [ i ] . vertex_BL . uv2 . y = yDelta + ( characterInfos [ i ] . vertex_BL . uv2 . x / characterInfos [ i ] . aspectRatio ) ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_TL . uv2 . y = yDelta + ( characterInfos [ i ] . vertex_TR . uv2 . x / characterInfos [ i ] . aspectRatio ) ; // + m_uvOffset.y;
characterInfos [ i ] . vertex_BR . uv2 . y = characterInfos [ i ] . vertex_BL . uv2 . y ;
characterInfos [ i ] . vertex_TR . uv2 . y = characterInfos [ i ] . vertex_TL . uv2 . y ;
break ;
}
#endregion
// Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio.
#region Pack Scale into UV2
xScale = characterInfos [ i ] . scale * Mathf . Abs ( lossyScale ) * ( 1 - m_charWidthAdjDelta ) ;
if ( ! characterInfos [ i ] . isUsingAlternateTypeface & & ( characterInfos [ i ] . style & FontStyles . Bold ) = = FontStyles . Bold ) xScale * = - 1 ;
//int isBold = (m_textInfo.characterInfo[i].style & FontStyles.Bold) == FontStyles.Bold ? 1 : 0;
//Vector2 vertexData = new Vector2(isBold, xScale);
//characterInfos[i].vertex_BL.uv4 = vertexData;
//characterInfos[i].vertex_TL.uv4 = vertexData;
//characterInfos[i].vertex_TR.uv4 = vertexData;
//characterInfos[i].vertex_BR.uv4 = vertexData;
float x0 = characterInfos [ i ] . vertex_BL . uv2 . x ;
float y0 = characterInfos [ i ] . vertex_BL . uv2 . y ;
float x1 = characterInfos [ i ] . vertex_TR . uv2 . x ;
float y1 = characterInfos [ i ] . vertex_TR . uv2 . y ;
float dx = ( int ) x0 ;
float dy = ( int ) y0 ;
x0 = x0 - dx ;
x1 = x1 - dx ;
y0 = y0 - dy ;
y1 = y1 - dy ;
// Optimization to avoid having a vector2 returned from the Pack UV function.
characterInfos [ i ] . vertex_BL . uv2 . x = PackUV ( x0 , y0 ) ; characterInfos [ i ] . vertex_BL . uv2 . y = xScale ;
characterInfos [ i ] . vertex_TL . uv2 . x = PackUV ( x0 , y1 ) ; characterInfos [ i ] . vertex_TL . uv2 . y = xScale ;
characterInfos [ i ] . vertex_TR . uv2 . x = PackUV ( x1 , y1 ) ; characterInfos [ i ] . vertex_TR . uv2 . y = xScale ;
characterInfos [ i ] . vertex_BR . uv2 . x = PackUV ( x1 , y0 ) ; characterInfos [ i ] . vertex_BR . uv2 . y = xScale ;
#endregion
break ;
// SPRITES
case TMP_TextElementType . Sprite :
// Nothing right now
break ;
}
// Handle maxVisibleCharacters, maxVisibleLines and Overflow Page Mode.
#region Handle maxVisibleCharacters / maxVisibleLines / Page Mode
if ( i < m_maxVisibleCharacters & & wordCount < m_maxVisibleWords & & currentLine < m_maxVisibleLines & & m_overflowMode ! = TextOverflowModes . Page )
{
characterInfos [ i ] . vertex_BL . position + = offset ;
characterInfos [ i ] . vertex_TL . position + = offset ;
characterInfos [ i ] . vertex_TR . position + = offset ;
characterInfos [ i ] . vertex_BR . position + = offset ;
}
else if ( i < m_maxVisibleCharacters & & wordCount < m_maxVisibleWords & & currentLine < m_maxVisibleLines & & m_overflowMode = = TextOverflowModes . Page & & characterInfos [ i ] . pageNumber = = pageToDisplay )
{
characterInfos [ i ] . vertex_BL . position + = offset ;
characterInfos [ i ] . vertex_TL . position + = offset ;
characterInfos [ i ] . vertex_TR . position + = offset ;
characterInfos [ i ] . vertex_BR . position + = offset ;
}
else
{
characterInfos [ i ] . vertex_BL . position = Vector3 . zero ;
characterInfos [ i ] . vertex_TL . position = Vector3 . zero ;
characterInfos [ i ] . vertex_TR . position = Vector3 . zero ;
characterInfos [ i ] . vertex_BR . position = Vector3 . zero ;
characterInfos [ i ] . isVisible = false ;
}
#endregion
// Fill Vertex Buffers for the various types of element
if ( elementType = = TMP_TextElementType . Character )
{
2022-01-12 10:39:15 +03:00
FillCharacterVertexBuffers ( i , vert_index_X4 ) ;
2022-01-12 10:06:03 +03:00
}
else if ( elementType = = TMP_TextElementType . Sprite )
{
FillSpriteVertexBuffers ( i , sprite_index_X4 ) ;
}
}
#endregion
// Apply Alignment and Justification Offset
m_textInfo . characterInfo [ i ] . bottomLeft + = offset ;
m_textInfo . characterInfo [ i ] . topLeft + = offset ;
m_textInfo . characterInfo [ i ] . topRight + = offset ;
m_textInfo . characterInfo [ i ] . bottomRight + = offset ;
m_textInfo . characterInfo [ i ] . origin + = offset . x ;
m_textInfo . characterInfo [ i ] . xAdvance + = offset . x ;
m_textInfo . characterInfo [ i ] . ascender + = offset . y ;
m_textInfo . characterInfo [ i ] . descender + = offset . y ;
m_textInfo . characterInfo [ i ] . baseLine + = offset . y ;
// Update MeshExtents
if ( isCharacterVisible )
{
//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));
//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));
}
// Need to recompute lineExtent to account for the offset from justification.
#region Adjust lineExtents resulting from alignment offset
if ( currentLine ! = lastLine | | i = = m_characterCount - 1 )
{
// Update the previous line's extents
if ( currentLine ! = lastLine )
{
m_textInfo . lineInfo [ lastLine ] . baseline + = offset . y ;
m_textInfo . lineInfo [ lastLine ] . ascender + = offset . y ;
m_textInfo . lineInfo [ lastLine ] . descender + = offset . y ;
m_textInfo . lineInfo [ lastLine ] . maxAdvance + = offset . x ;
m_textInfo . lineInfo [ lastLine ] . lineExtents . min = new Vector2 ( m_textInfo . characterInfo [ m_textInfo . lineInfo [ lastLine ] . firstCharacterIndex ] . bottomLeft . x , m_textInfo . lineInfo [ lastLine ] . descender ) ;
m_textInfo . lineInfo [ lastLine ] . lineExtents . max = new Vector2 ( m_textInfo . characterInfo [ m_textInfo . lineInfo [ lastLine ] . lastVisibleCharacterIndex ] . topRight . x , m_textInfo . lineInfo [ lastLine ] . ascender ) ;
}
// Update the current line's extents
if ( i = = m_characterCount - 1 )
{
m_textInfo . lineInfo [ currentLine ] . baseline + = offset . y ;
m_textInfo . lineInfo [ currentLine ] . ascender + = offset . y ;
m_textInfo . lineInfo [ currentLine ] . descender + = offset . y ;
m_textInfo . lineInfo [ currentLine ] . maxAdvance + = offset . x ;
m_textInfo . lineInfo [ currentLine ] . lineExtents . min = new Vector2 ( m_textInfo . characterInfo [ m_textInfo . lineInfo [ currentLine ] . firstCharacterIndex ] . bottomLeft . x , m_textInfo . lineInfo [ currentLine ] . descender ) ;
m_textInfo . lineInfo [ currentLine ] . lineExtents . max = new Vector2 ( m_textInfo . characterInfo [ m_textInfo . lineInfo [ currentLine ] . lastVisibleCharacterIndex ] . topRight . x , m_textInfo . lineInfo [ currentLine ] . ascender ) ;
}
}
#endregion
// Track Word Count per line and for the object
#region Track Word Count
if ( char . IsLetterOrDigit ( unicode ) | | unicode = = 0x2D | | unicode = = 0xAD | | unicode = = 0x2010 | | unicode = = 0x2011 )
{
if ( isStartOfWord = = false )
{
isStartOfWord = true ;
wordFirstChar = i ;
}
// If last character is a word
if ( isStartOfWord & & i = = m_characterCount - 1 )
{
int size = m_textInfo . wordInfo . Length ;
int index = m_textInfo . wordCount ;
if ( m_textInfo . wordCount + 1 > size )
TMP_TextInfo . Resize ( ref m_textInfo . wordInfo , size + 1 ) ;
wordLastChar = i ;
m_textInfo . wordInfo [ index ] . firstCharacterIndex = wordFirstChar ;
m_textInfo . wordInfo [ index ] . lastCharacterIndex = wordLastChar ;
m_textInfo . wordInfo [ index ] . characterCount = wordLastChar - wordFirstChar + 1 ;
m_textInfo . wordInfo [ index ] . textComponent = this ;
wordCount + = 1 ;
m_textInfo . wordCount + = 1 ;
m_textInfo . lineInfo [ currentLine ] . wordCount + = 1 ;
}
}
else if ( isStartOfWord | | i = = 0 & & ( ! char . IsPunctuation ( unicode ) | | char . IsWhiteSpace ( unicode ) | | unicode = = 0x200B | | i = = m_characterCount - 1 ) )
{
if ( i > 0 & & i < characterInfos . Length - 1 & & i < m_characterCount & & ( unicode = = 39 | | unicode = = 8217 ) & & char . IsLetterOrDigit ( characterInfos [ i - 1 ] . character ) & & char . IsLetterOrDigit ( characterInfos [ i + 1 ] . character ) )
{
}
else
{
wordLastChar = i = = m_characterCount - 1 & & char . IsLetterOrDigit ( unicode ) ? i : i - 1 ;
isStartOfWord = false ;
int size = m_textInfo . wordInfo . Length ;
int index = m_textInfo . wordCount ;
if ( m_textInfo . wordCount + 1 > size )
TMP_TextInfo . Resize ( ref m_textInfo . wordInfo , size + 1 ) ;
m_textInfo . wordInfo [ index ] . firstCharacterIndex = wordFirstChar ;
m_textInfo . wordInfo [ index ] . lastCharacterIndex = wordLastChar ;
m_textInfo . wordInfo [ index ] . characterCount = wordLastChar - wordFirstChar + 1 ;
m_textInfo . wordInfo [ index ] . textComponent = this ;
wordCount + = 1 ;
m_textInfo . wordCount + = 1 ;
m_textInfo . lineInfo [ currentLine ] . wordCount + = 1 ;
}
}
#endregion
// Setup & Handle Underline
#region Underline
// NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
bool isUnderline = ( m_textInfo . characterInfo [ i ] . style & FontStyles . Underline ) = = FontStyles . Underline ;
if ( isUnderline )
{
bool isUnderlineVisible = true ;
int currentPage = m_textInfo . characterInfo [ i ] . pageNumber ;
m_textInfo . characterInfo [ i ] . underlineVertexIndex = last_vert_index ;
if ( i > m_maxVisibleCharacters | | currentLine > m_maxVisibleLines | | ( m_overflowMode = = TextOverflowModes . Page & & currentPage + 1 ! = m_pageToDisplay ) )
isUnderlineVisible = false ;
// We only use the scale of visible characters.
if ( ! char . IsWhiteSpace ( unicode ) & & unicode ! = 0x200B )
{
underlineMaxScale = Mathf . Max ( underlineMaxScale , m_textInfo . characterInfo [ i ] . scale ) ;
xScaleMax = Mathf . Max ( xScaleMax , Mathf . Abs ( xScale ) ) ;
underlineBaseLine = Mathf . Min ( currentPage = = lastPage ? underlineBaseLine : k_LargePositiveFloat , m_textInfo . characterInfo [ i ] . baseLine + font . m_FaceInfo . underlineOffset * underlineMaxScale ) ;
lastPage = currentPage ; // Need to track pages to ensure we reset baseline for the new pages.
}
if ( beginUnderline = = false & & isUnderlineVisible = = true & & i < = lineInfo . lastVisibleCharacterIndex & & unicode ! = 10 & & unicode ! = 11 & & unicode ! = 13 )
{
if ( i = = lineInfo . lastVisibleCharacterIndex & & char . IsSeparator ( unicode ) )
{ }
else
{
beginUnderline = true ;
underlineStartScale = m_textInfo . characterInfo [ i ] . scale ;
if ( underlineMaxScale = = 0 )
{
underlineMaxScale = underlineStartScale ;
xScaleMax = xScale ;
}
underline_start = new Vector3 ( m_textInfo . characterInfo [ i ] . bottomLeft . x , underlineBaseLine , 0 ) ;
underlineColor = m_textInfo . characterInfo [ i ] . underlineColor ;
}
}
// End Underline if text only contains one character.
if ( beginUnderline & & m_characterCount = = 1 )
{
beginUnderline = false ;
underline_end = new Vector3 ( m_textInfo . characterInfo [ i ] . topRight . x , underlineBaseLine , 0 ) ;
underlineEndScale = m_textInfo . characterInfo [ i ] . scale ;
DrawUnderlineMesh ( underline_start , underline_end , ref last_vert_index , underlineStartScale , underlineEndScale , underlineMaxScale , xScaleMax , underlineColor ) ;
underlineMaxScale = 0 ;
xScaleMax = 0 ;
underlineBaseLine = k_LargePositiveFloat ;
}
else if ( beginUnderline & & ( i = = lineInfo . lastCharacterIndex | | i > = lineInfo . lastVisibleCharacterIndex ) )
{
// Terminate underline at previous visible character if space or carriage return.
if ( char . IsWhiteSpace ( unicode ) | | unicode = = 0x200B )
{
int lastVisibleCharacterIndex = lineInfo . lastVisibleCharacterIndex ;
underline_end = new Vector3 ( m_textInfo . characterInfo [ lastVisibleCharacterIndex ] . topRight . x , underlineBaseLine , 0 ) ;
underlineEndScale = m_textInfo . characterInfo [ lastVisibleCharacterIndex ] . scale ;
}
else
{ // End underline if last character of the line.
underline_end = new Vector3 ( m_textInfo . characterInfo [ i ] . topRight . x , underlineBaseLine , 0 ) ;
underlineEndScale = m_textInfo . characterInfo [ i ] . scale ;
}
beginUnderline = false ;
DrawUnderlineMesh ( underline_start , underline_end , ref last_vert_index , underlineStartScale , underlineEndScale , underlineMaxScale , xScaleMax , underlineColor ) ;
underlineMaxScale = 0 ;
xScaleMax = 0 ;
underlineBaseLine = k_LargePositiveFloat ;
}
else if ( beginUnderline & & ! isUnderlineVisible )
{
beginUnderline = false ;
underline_end = new Vector3 ( m_textInfo . characterInfo [ i - 1 ] . topRight . x , underlineBaseLine , 0 ) ;
underlineEndScale = m_textInfo . characterInfo [ i - 1 ] . scale ;
DrawUnderlineMesh ( underline_start , underline_end , ref last_vert_index , underlineStartScale , underlineEndScale , underlineMaxScale , xScaleMax , underlineColor ) ;
underlineMaxScale = 0 ;
xScaleMax = 0 ;
underlineBaseLine = k_LargePositiveFloat ;
}
else if ( beginUnderline & & i < m_characterCount - 1 & & ! underlineColor . Compare ( m_textInfo . characterInfo [ i + 1 ] . underlineColor ) )
{
// End underline if underline color has changed.
beginUnderline = false ;
underline_end = new Vector3 ( m_textInfo . characterInfo [ i ] . topRight . x , underlineBaseLine , 0 ) ;
underlineEndScale = m_textInfo . characterInfo [ i ] . scale ;
DrawUnderlineMesh ( underline_start , underline_end , ref last_vert_index , underlineStartScale , underlineEndScale , underlineMaxScale , xScaleMax , underlineColor ) ;
underlineMaxScale = 0 ;
xScaleMax = 0 ;
underlineBaseLine = k_LargePositiveFloat ;
}
}
else
{
// End Underline
if ( beginUnderline = = true )
{
beginUnderline = false ;
underline_end = new Vector3 ( m_textInfo . characterInfo [ i - 1 ] . topRight . x , underlineBaseLine , 0 ) ;
underlineEndScale = m_textInfo . characterInfo [ i - 1 ] . scale ;
DrawUnderlineMesh ( underline_start , underline_end , ref last_vert_index , underlineStartScale , underlineEndScale , underlineMaxScale , xScaleMax , underlineColor ) ;
underlineMaxScale = 0 ;
xScaleMax = 0 ;
underlineBaseLine = k_LargePositiveFloat ;
}
}
#endregion
// Setup & Handle Strikethrough
#region Strikethrough
// NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
bool isStrikethrough = ( m_textInfo . characterInfo [ i ] . style & FontStyles . Strikethrough ) = = FontStyles . Strikethrough ;
float strikethroughOffset = currentFontAsset . m_FaceInfo . strikethroughOffset ;
if ( isStrikethrough )
{
bool isStrikeThroughVisible = true ;
m_textInfo . characterInfo [ i ] . strikethroughVertexIndex = last_vert_index ;
if ( i > m_maxVisibleCharacters | | currentLine > m_maxVisibleLines | | ( m_overflowMode = = TextOverflowModes . Page & & m_textInfo . characterInfo [ i ] . pageNumber + 1 ! = m_pageToDisplay ) )
isStrikeThroughVisible = false ;
if ( beginStrikethrough = = false & & isStrikeThroughVisible & & i < = lineInfo . lastVisibleCharacterIndex & & unicode ! = 10 & & unicode ! = 11 & & unicode ! = 13 )
{
if ( i = = lineInfo . lastVisibleCharacterIndex & & char . IsSeparator ( unicode ) )
{ }
else
{
beginStrikethrough = true ;
strikethroughPointSize = m_textInfo . characterInfo [ i ] . pointSize ;
strikethroughScale = m_textInfo . characterInfo [ i ] . scale ;
strikethrough_start = new Vector3 ( m_textInfo . characterInfo [ i ] . bottomLeft . x , m_textInfo . characterInfo [ i ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
strikethroughColor = m_textInfo . characterInfo [ i ] . strikethroughColor ;
strikethroughBaseline = m_textInfo . characterInfo [ i ] . baseLine ;
//Debug.Log("Char [" + currentCharacter + "] Start Strikethrough POS: " + strikethrough_start);
}
}
// End Strikethrough if text only contains one character.
if ( beginStrikethrough & & m_characterCount = = 1 )
{
beginStrikethrough = false ;
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ i ] . topRight . x , m_textInfo . characterInfo [ i ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
DrawUnderlineMesh ( strikethrough_start , strikethrough_end , ref last_vert_index , strikethroughScale , strikethroughScale , strikethroughScale , xScale , strikethroughColor ) ;
}
else if ( beginStrikethrough & & i = = lineInfo . lastCharacterIndex )
{
// Terminate Strikethrough at previous visible character if space or carriage return.
if ( char . IsWhiteSpace ( unicode ) | | unicode = = 0x200B )
{
int lastVisibleCharacterIndex = lineInfo . lastVisibleCharacterIndex ;
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ lastVisibleCharacterIndex ] . topRight . x , m_textInfo . characterInfo [ lastVisibleCharacterIndex ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
}
else
{
// Terminate Strikethrough at last character of line.
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ i ] . topRight . x , m_textInfo . characterInfo [ i ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
}
beginStrikethrough = false ;
DrawUnderlineMesh ( strikethrough_start , strikethrough_end , ref last_vert_index , strikethroughScale , strikethroughScale , strikethroughScale , xScale , strikethroughColor ) ;
}
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 ) ) )
{
// Terminate Strikethrough if scale changes.
beginStrikethrough = false ;
int lastVisibleCharacterIndex = lineInfo . lastVisibleCharacterIndex ;
if ( i > lastVisibleCharacterIndex )
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ lastVisibleCharacterIndex ] . topRight . x , m_textInfo . characterInfo [ lastVisibleCharacterIndex ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
else
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ i ] . topRight . x , m_textInfo . characterInfo [ i ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
DrawUnderlineMesh ( strikethrough_start , strikethrough_end , ref last_vert_index , strikethroughScale , strikethroughScale , strikethroughScale , xScale , strikethroughColor ) ;
//Debug.Log("Char [" + currentCharacter + "] at Index: " + i + " End Strikethrough POS: " + strikethrough_end + " Baseline: " + m_textInfo.characterInfo[i].baseLine.ToString("f3"));
}
else if ( beginStrikethrough & & i < m_characterCount & & currentFontAsset . GetInstanceID ( ) ! = characterInfos [ i + 1 ] . fontAsset . GetInstanceID ( ) )
{
// Terminate Strikethrough if font asset changes.
beginStrikethrough = false ;
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ i ] . topRight . x , m_textInfo . characterInfo [ i ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
DrawUnderlineMesh ( strikethrough_start , strikethrough_end , ref last_vert_index , strikethroughScale , strikethroughScale , strikethroughScale , xScale , strikethroughColor ) ;
}
else if ( beginStrikethrough & & ! isStrikeThroughVisible )
{
// Terminate Strikethrough if character is not visible.
beginStrikethrough = false ;
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ i - 1 ] . topRight . x , m_textInfo . characterInfo [ i - 1 ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
DrawUnderlineMesh ( strikethrough_start , strikethrough_end , ref last_vert_index , strikethroughScale , strikethroughScale , strikethroughScale , xScale , strikethroughColor ) ;
}
}
else
{
// End Strikethrough
if ( beginStrikethrough = = true )
{
beginStrikethrough = false ;
strikethrough_end = new Vector3 ( m_textInfo . characterInfo [ i - 1 ] . topRight . x , m_textInfo . characterInfo [ i - 1 ] . baseLine + strikethroughOffset * strikethroughScale , 0 ) ;
DrawUnderlineMesh ( strikethrough_start , strikethrough_end , ref last_vert_index , strikethroughScale , strikethroughScale , strikethroughScale , xScale , strikethroughColor ) ;
}
}
#endregion
// HANDLE TEXT HIGHLIGHTING
#region Text Highlighting
bool isHighlight = ( m_textInfo . characterInfo [ i ] . style & FontStyles . Highlight ) = = FontStyles . Highlight ;
if ( isHighlight )
{
bool isHighlightVisible = true ;
int currentPage = m_textInfo . characterInfo [ i ] . pageNumber ;
if ( i > m_maxVisibleCharacters | | currentLine > m_maxVisibleLines | | ( m_overflowMode = = TextOverflowModes . Page & & currentPage + 1 ! = m_pageToDisplay ) )
isHighlightVisible = false ;
if ( beginHighlight = = false & & isHighlightVisible = = true & & i < = lineInfo . lastVisibleCharacterIndex & & unicode ! = 10 & & unicode ! = 11 & & unicode ! = 13 )
{
if ( i = = lineInfo . lastVisibleCharacterIndex & & char . IsSeparator ( unicode ) )
{ }
else
{
beginHighlight = true ;
highlight_start = k_LargePositiveVector2 ;
highlight_end = k_LargeNegativeVector2 ;
highlightState = m_textInfo . characterInfo [ i ] . highlightState ;
}
}
if ( beginHighlight )
{
TMP_CharacterInfo currentCharacter = m_textInfo . characterInfo [ i ] ;
HighlightState currentState = currentCharacter . highlightState ;
bool isColorTransition = false ;
// Handle Highlight color changes
if ( highlightState ! = currentCharacter . highlightState )
{
// Adjust previous highlight section to prevent a gaps between sections.
highlight_end . x = ( highlight_end . x - highlightState . padding . right + currentCharacter . bottomLeft . x ) / 2 ;
highlight_start . y = Mathf . Min ( highlight_start . y , currentCharacter . descender ) ;
highlight_end . y = Mathf . Max ( highlight_end . y , currentCharacter . ascender ) ;
DrawTextHighlight ( highlight_start , highlight_end , ref last_vert_index , highlightState . color ) ;
beginHighlight = true ;
highlight_start = new Vector2 ( highlight_end . x , currentCharacter . descender - currentState . padding . bottom ) ;
highlight_end = new Vector2 ( currentCharacter . topRight . x + currentState . padding . right , currentCharacter . ascender + currentState . padding . top ) ;
highlightState = currentCharacter . highlightState ;
isColorTransition = true ;
}
if ( ! isColorTransition )
{
// Use the Min / Max Extents of the Highlight area to handle different character sizes and fonts.
highlight_start . x = Mathf . Min ( highlight_start . x , currentCharacter . bottomLeft . x - highlightState . padding . left ) ;
highlight_start . y = Mathf . Min ( highlight_start . y , currentCharacter . descender - highlightState . padding . bottom ) ;
highlight_end . x = Mathf . Max ( highlight_end . x , currentCharacter . topRight . x + highlightState . padding . right ) ;
highlight_end . y = Mathf . Max ( highlight_end . y , currentCharacter . ascender + highlightState . padding . top ) ;
}
}
// End Highlight if text only contains one character.
if ( beginHighlight & & m_characterCount = = 1 )
{
beginHighlight = false ;
DrawTextHighlight ( highlight_start , highlight_end , ref last_vert_index , highlightState . color ) ;
}
else if ( beginHighlight & & ( i = = lineInfo . lastCharacterIndex | | i > = lineInfo . lastVisibleCharacterIndex ) )
{
beginHighlight = false ;
DrawTextHighlight ( highlight_start , highlight_end , ref last_vert_index , highlightState . color ) ;
}
else if ( beginHighlight & & ! isHighlightVisible )
{
beginHighlight = false ;
DrawTextHighlight ( highlight_start , highlight_end , ref last_vert_index , highlightState . color ) ;
}
}
else
{
// End Highlight
if ( beginHighlight = = true )
{
beginHighlight = false ;
DrawTextHighlight ( highlight_start , highlight_end , ref last_vert_index , highlightState . color ) ;
}
}
#endregion
lastLine = currentLine ;
}
#endregion
// Set vertex count for Underline geometry
//m_textInfo.meshInfo[m_Underline.materialIndex].vertexCount = last_vert_index;
// METRICS ABOUT THE TEXT OBJECT
m_textInfo . characterCount = m_characterCount ;
m_textInfo . spriteCount = m_spriteCount ;
m_textInfo . lineCount = lineCount ;
m_textInfo . wordCount = wordCount ! = 0 & & m_characterCount > 0 ? wordCount : 1 ;
m_textInfo . pageCount = m_pageNumber + 1 ;
// End Sampling of Phase II
2022-01-12 10:39:15 +03:00
k_GenerateTextPhaseIIMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
// Phase III - Update Mesh Vertex Data
2022-01-12 10:39:15 +03:00
k_GenerateTextPhaseIIIMarker . Begin ( ) ;
2022-01-12 10:06:03 +03:00
if ( m_renderMode = = TextRenderFlags . Render & & IsActive ( ) )
{
// Event to allow users to modify the content of the text info before the text is rendered.
OnPreRenderText ? . Invoke ( m_textInfo ) ;
// Sort the geometry of the text object if needed.
if ( m_geometrySortingOrder ! = VertexSortingOrder . Normal )
m_textInfo . meshInfo [ 0 ] . SortGeometry ( VertexSortingOrder . Reverse ) ;
// Upload Mesh Data
m_mesh . MarkDynamic ( ) ;
m_mesh . vertices = m_textInfo . meshInfo [ 0 ] . vertices ;
m_mesh . uv = m_textInfo . meshInfo [ 0 ] . uvs0 ;
m_mesh . uv2 = m_textInfo . meshInfo [ 0 ] . uvs2 ;
//m_mesh.uv4 = m_textInfo.meshInfo[0].uvs4;
m_mesh . colors32 = m_textInfo . meshInfo [ 0 ] . colors32 ;
2022-01-12 10:39:15 +03:00
// Compute Bounds for the mesh. Manual computation is more efficient then using Mesh.RecalcualteBounds.
2022-01-12 10:06:03 +03:00
m_mesh . RecalculateBounds ( ) ;
//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));
for ( int i = 1 ; i < m_textInfo . materialCount ; i + + )
{
// Clear unused vertices
m_textInfo . meshInfo [ i ] . ClearUnusedVertices ( ) ;
if ( m_subTextObjects [ i ] = = null ) continue ;
// Sort the geometry of the sub-text objects if needed.
if ( m_geometrySortingOrder ! = VertexSortingOrder . Normal )
m_textInfo . meshInfo [ i ] . SortGeometry ( VertexSortingOrder . Reverse ) ;
m_subTextObjects [ i ] . mesh . vertices = m_textInfo . meshInfo [ i ] . vertices ;
m_subTextObjects [ i ] . mesh . uv = m_textInfo . meshInfo [ i ] . uvs0 ;
m_subTextObjects [ i ] . mesh . uv2 = m_textInfo . meshInfo [ i ] . uvs2 ;
//m_subTextObjects[i].mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
m_subTextObjects [ i ] . mesh . colors32 = m_textInfo . meshInfo [ i ] . colors32 ;
m_subTextObjects [ i ] . mesh . RecalculateBounds ( ) ;
// Update the collider on the sub text object
//m_subTextObjects[i].UpdateColliders(m_textInfo.meshInfo[i].vertexCount);
}
}
// Event indicating the text has been regenerated.
TMPro_EventManager . ON_TEXT_CHANGED ( this ) ;
//Debug.Log("***** Done rendering text object ID " + GetInstanceID() + ". *****");
2022-01-12 10:39:15 +03:00
// Clear allocations no longer necessary given the text object is static
// if (true)
// {
// m_isInputParsingRequired = true;
// m_textInfo.ClearAllData();
// }
2022-01-12 10:06:03 +03:00
2022-01-12 10:39:15 +03:00
// End Sampling
k_GenerateTextPhaseIIIMarker . End ( ) ;
k_GenerateTextMarker . End ( ) ;
2022-01-12 10:06:03 +03:00
}
/// <summary>
/// Method to return the local corners of the Text Container or RectTransform.
/// </summary>
/// <returns></returns>
protected override Vector3 [ ] GetTextContainerLocalCorners ( )
{
if ( m_rectTransform = = null ) m_rectTransform = this . rectTransform ;
m_rectTransform . GetLocalCorners ( m_RectTransformCorners ) ;
return m_RectTransformCorners ;
}
/// <summary>
/// Method to disable the renderers.
/// </summary>
void SetMeshFilters ( bool state )
{
// Parent text object
if ( m_meshFilter ! = null )
{
if ( state )
m_meshFilter . sharedMesh = m_mesh ;
else
m_meshFilter . sharedMesh = null ;
}
for ( int i = 1 ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
{
if ( m_subTextObjects [ i ] . meshFilter ! = null )
{
if ( state )
m_subTextObjects [ i ] . meshFilter . sharedMesh = m_subTextObjects [ i ] . mesh ;
else
m_subTextObjects [ i ] . meshFilter . sharedMesh = null ;
}
}
}
/// <summary>
/// Method to Enable or Disable child SubMesh objects.
/// </summary>
/// <param name="state"></param>
protected override void SetActiveSubMeshes ( bool state )
{
for ( int i = 1 ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
{
if ( m_subTextObjects [ i ] . enabled ! = state )
m_subTextObjects [ i ] . enabled = state ;
}
}
protected void SetActiveSubTextObjectRenderers ( bool state )
{
for ( int i = 1 ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
{
2022-01-12 10:39:15 +03:00
Renderer subMeshRenderer = m_subTextObjects [ i ] . renderer ;
2022-01-12 10:06:03 +03:00
2022-01-12 10:39:15 +03:00
if ( subMeshRenderer ! = null & & subMeshRenderer . enabled ! = state )
subMeshRenderer . enabled = state ;
2022-01-12 10:06:03 +03:00
}
}
/// <summary>
/// Destroy Sub Mesh Objects
/// </summary>
protected override void DestroySubMeshObjects ( )
{
for ( int i = 1 ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
DestroyImmediate ( m_subTextObjects [ i ] ) ;
}
2022-01-12 10:39:15 +03:00
/// <summary>
///
/// </summary>
internal void UpdateSubMeshSortingLayerID ( int id )
{
for ( int i = 1 ; i < m_subTextObjects . Length ; i + + )
{
TMP_SubMesh subMesh = m_subTextObjects [ i ] ;
if ( subMesh ! = null & & subMesh . renderer ! = null )
{
subMesh . renderer . sortingLayerID = id ;
}
}
}
/// <summary>
///
/// </summary>
internal void UpdateSubMeshSortingOrder ( int order )
{
for ( int i = 1 ; i < m_subTextObjects . Length ; i + + )
{
TMP_SubMesh subMesh = m_subTextObjects [ i ] ;
if ( subMesh ! = null & & subMesh . renderer ! = null )
{
subMesh . renderer . sortingOrder = order ;
}
}
}
2022-01-12 10:06:03 +03:00
/// <summary>
/// Method returning the compound bounds of the text object and child sub objects.
/// </summary>
/// <returns></returns>
protected override Bounds GetCompoundBounds ( )
{
Bounds mainBounds = m_mesh . bounds ;
Vector3 min = mainBounds . min ;
Vector3 max = mainBounds . max ;
for ( int i = 1 ; i < m_subTextObjects . Length & & m_subTextObjects [ i ] ! = null ; i + + )
{
Bounds subBounds = m_subTextObjects [ i ] . mesh . bounds ;
min . x = min . x < subBounds . min . x ? min . x : subBounds . min . x ;
min . y = min . y < subBounds . min . y ? min . y : subBounds . min . y ;
max . x = max . x > subBounds . max . x ? max . x : subBounds . max . x ;
max . y = max . y > subBounds . max . y ? max . y : subBounds . max . y ;
}
Vector3 center = ( min + max ) / 2 ;
Vector2 size = max - min ;
return new Bounds ( center , size ) ;
}
/// <summary>
/// Method to Update Scale in UV2
/// </summary>
//void UpdateSDFScale(float lossyScale)
//{
// // TODO: Resolve - Underline / Strikethrough segments not getting their SDF Scale adjusted.
// //Debug.Log("*** UpdateSDFScale() ***");
// // Iterate through each of the characters.
// for (int i = 0; i < m_textInfo.characterCount; i++)
// {
// // Only update scale for visible characters.
// if (m_textInfo.characterInfo[i].isVisible && m_textInfo.characterInfo[i].elementType == TMP_TextElementType.Character)
// {
// float scale = lossyScale * m_textInfo.characterInfo[i].scale * (1 - m_charWidthAdjDelta);
// if (!m_textInfo.characterInfo[i].isUsingAlternateTypeface && (m_textInfo.characterInfo[i].style & FontStyles.Bold) == FontStyles.Bold) scale *= -1;
// int index = m_textInfo.characterInfo[i].materialReferenceIndex;
// int vertexIndex = m_textInfo.characterInfo[i].vertexIndex;
// m_textInfo.meshInfo[index].uvs2[vertexIndex + 0].y = scale;
// m_textInfo.meshInfo[index].uvs2[vertexIndex + 1].y = scale;
// m_textInfo.meshInfo[index].uvs2[vertexIndex + 2].y = scale;
// m_textInfo.meshInfo[index].uvs2[vertexIndex + 3].y = scale;
// }
// }
// // Push the updated uv2 scale information to the meshes.
// for (int i = 0; i < m_textInfo.meshInfo.Length; i++)
// {
// if (i == 0)
// m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
// else
// m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
// }
//}
/// <summary>
/// Method to update the SDF Scale in UV2.
/// </summary>
/// <param name="scaleDelta"></param>
void UpdateSDFScale ( float scaleDelta )
{
if ( scaleDelta = = 0 | | scaleDelta = = float . PositiveInfinity | | scaleDelta = = float . NegativeInfinity )
{
m_havePropertiesChanged = true ;
OnPreRenderObject ( ) ;
return ;
}
for ( int materialIndex = 0 ; materialIndex < m_textInfo . materialCount ; materialIndex + + )
{
TMP_MeshInfo meshInfo = m_textInfo . meshInfo [ materialIndex ] ;
for ( int i = 0 ; i < meshInfo . uvs2 . Length ; i + + )
{
meshInfo . uvs2 [ i ] . y * = Mathf . Abs ( scaleDelta ) ;
}
}
// Push the updated uv2 scale information to the meshes.
for ( int i = 0 ; i < m_textInfo . meshInfo . Length ; i + + )
{
if ( i = = 0 )
m_mesh . uv2 = m_textInfo . meshInfo [ 0 ] . uvs2 ;
else
m_subTextObjects [ i ] . mesh . uv2 = m_textInfo . meshInfo [ i ] . uvs2 ;
}
}
}
}