#define TMP_PRESENT using UnityEngine; using UnityEngine.UI; using UnityEngine.Events; using UnityEngine.EventSystems; using System; using System.Text; using System.Collections; using System.Collections.Generic; namespace TMPro { public interface ITextElement { Material sharedMaterial { get; } void Rebuild(CanvasUpdate update); int GetInstanceID(); } public enum TextAlignmentOptions { TopLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Top, Top = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Top, TopRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Top, TopJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Top, TopFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Top, TopGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Top, Left = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Middle, Center = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Middle, Right = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Middle, Justified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Middle, Flush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Middle, CenterGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Middle, BottomLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Bottom, Bottom = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Bottom, BottomRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Bottom, BottomJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Bottom, BottomFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Bottom, BottomGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Bottom, BaselineLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Baseline, Baseline = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Baseline, BaselineRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Baseline, BaselineJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Baseline, BaselineFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Baseline, BaselineGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Baseline, MidlineLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Geometry, Midline = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Geometry, MidlineRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Geometry, MidlineJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Geometry, MidlineFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Geometry, MidlineGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Geometry, CaplineLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Capline, Capline = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Capline, CaplineRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Capline, CaplineJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Capline, CaplineFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Capline, CaplineGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Capline }; /// /// Internal horizontal text alignment options. /// public enum _HorizontalAlignmentOptions { Left = 0x1, Center = 0x2, Right = 0x4, Justified = 0x8, Flush = 0x10, Geometry = 0x20 } /// /// Internal vertical text alignment options. /// public enum _VerticalAlignmentOptions { Top = 0x100, Middle = 0x200, Bottom = 0x400, Baseline = 0x800, Geometry = 0x1000, Capline = 0x2000, } /// /// Flags controlling what vertex data gets pushed to the mesh. /// public enum TextRenderFlags { DontRender = 0x0, Render = 0xFF }; public enum TMP_TextElementType { Character, Sprite }; public enum MaskingTypes { MaskOff = 0, MaskHard = 1, MaskSoft = 2 }; //, MaskTex = 4 }; public enum TextOverflowModes { Overflow = 0, Ellipsis = 1, Masking = 2, Truncate = 3, ScrollRect = 4, Page = 5, Linked = 6 }; public enum MaskingOffsetMode { Percentage = 0, Pixel = 1 }; public enum TextureMappingOptions { Character = 0, Line = 1, Paragraph = 2, MatchAspect = 3 }; public enum FontStyles { Normal = 0x0, Bold = 0x1, Italic = 0x2, Underline = 0x4, LowerCase = 0x8, UpperCase = 0x10, SmallCaps = 0x20, Strikethrough = 0x40, Superscript = 0x80, Subscript = 0x100, Highlight = 0x200 }; public enum FontWeights { Thin = 100, ExtraLight = 200, Light = 300, Normal = 400, Medium = 500, SemiBold = 600, Bold = 700, Heavy = 800, Black = 900 }; public enum TagUnits { Pixels = 0, FontUnits = 1, Percentage = 2 }; public enum TagType { None = 0x0, NumericalValue = 0x1, StringValue = 0x2, ColorValue = 0x4 }; /// /// Base class which contains common properties and functions shared between the TextMeshPro and TextMeshProUGUI component. /// public abstract class TMP_Text : MaskableGraphic { /// /// A string containing the text to be displayed. /// public string text { get { return m_text; } set { if (m_text == value) return; m_text = old_text = value; m_inputSource = TextInputSources.String; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] [TextArea(3, 10)] protected string m_text; /// /// /// public bool isRightToLeftText { get { return m_isRightToLeft; } set { if (m_isRightToLeft == value) return; m_isRightToLeft = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_isRightToLeft = false; /// /// The Font Asset to be assigned to this text object. /// public TMP_FontAsset font { get { return m_fontAsset; } set { if (m_fontAsset == value) return; m_fontAsset = value; LoadFontAsset(); m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected TMP_FontAsset m_fontAsset; protected TMP_FontAsset m_currentFontAsset; protected bool m_isSDFShader; /// /// The material to be assigned to this text object. /// public virtual Material fontSharedMaterial { get { return m_sharedMaterial; } set { if (m_sharedMaterial == value) return; SetSharedMaterial(value); m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetMaterialDirty(); } } [SerializeField] protected Material m_sharedMaterial; protected Material m_currentMaterial; protected MaterialReference[] m_materialReferences = new MaterialReference[32]; protected Dictionary m_materialReferenceIndexLookup = new Dictionary(); protected TMP_XmlTagStack m_materialReferenceStack = new TMP_XmlTagStack(new MaterialReference[16]); protected int m_currentMaterialIndex; //protected int m_sharedMaterialHashCode; /// /// An array containing the materials used by the text object. /// public virtual Material[] fontSharedMaterials { get { return GetSharedMaterials(); } set { SetSharedMaterials(value); m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetMaterialDirty(); } } [SerializeField] protected Material[] m_fontSharedMaterials; /// /// The material to be assigned to this text object. An instance of the material will be assigned to the object's renderer. /// public Material fontMaterial { // Return an Instance of the current material. get { return GetMaterial(m_sharedMaterial); } // Assign new font material set { if (m_sharedMaterial != null && m_sharedMaterial.GetInstanceID() == value.GetInstanceID()) return; m_sharedMaterial = value; m_padding = GetPaddingForMaterial(); m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetMaterialDirty(); } } [SerializeField] protected Material m_fontMaterial; /// /// The materials to be assigned to this text object. An instance of the materials will be assigned. /// public virtual Material[] fontMaterials { get { return GetMaterials(m_fontSharedMaterials); } set { SetSharedMaterials(value); m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetMaterialDirty(); } } [SerializeField] protected Material[] m_fontMaterials; protected bool m_isMaterialDirty; /// /// This is the default vertex color assigned to each vertices. Color tags will override vertex colors unless the overrideColorTags is set. /// public override Color color { get { return m_fontColor; } set { if (m_fontColor == value) return; m_havePropertiesChanged = true; m_fontColor = value; SetVerticesDirty(); } } //[UnityEngine.Serialization.FormerlySerializedAs("m_fontColor")] // Required for backwards compatibility with pre-Unity 4.6 releases. [SerializeField] protected Color32 m_fontColor32 = Color.white; [SerializeField] protected Color m_fontColor = Color.white; protected static Color32 s_colorWhite = new Color32(255, 255, 255, 255); protected Color32 m_underlineColor = s_colorWhite; protected Color32 m_strikethroughColor = s_colorWhite; protected Color32 m_highlightColor = s_colorWhite; /// /// Sets the vertex color alpha value. /// public float alpha { get { return m_fontColor.a; } set { if (m_fontColor.a == value) return; m_fontColor.a = value; m_havePropertiesChanged = true; SetVerticesDirty(); } } /// /// Determines if Vertex Color Gradient should be used /// /// true if enable vertex gradient; otherwise, false. public bool enableVertexGradient { get { return m_enableVertexGradient; } set { if (m_enableVertexGradient == value) return; m_havePropertiesChanged = true; m_enableVertexGradient = value; SetVerticesDirty(); } } [SerializeField] protected bool m_enableVertexGradient; [SerializeField] protected ColorMode m_colorMode = ColorMode.FourCornersGradient; /// /// Sets the vertex colors for each of the 4 vertices of the character quads. /// /// The color gradient. public VertexGradient colorGradient { get { return m_fontColorGradient; } set { m_havePropertiesChanged = true; m_fontColorGradient = value; SetVerticesDirty(); } } [SerializeField] protected VertexGradient m_fontColorGradient = new VertexGradient(Color.white); /// /// Set the vertex colors of the 4 vertices of each character quads. /// public TMP_ColorGradient colorGradientPreset { get { return m_fontColorGradientPreset; } set { m_havePropertiesChanged = true; m_fontColorGradientPreset = value; SetVerticesDirty(); } } [SerializeField] protected TMP_ColorGradient m_fontColorGradientPreset; /// /// Default Sprite Asset used by the text object. /// public TMP_SpriteAsset spriteAsset { get { return m_spriteAsset; } set { m_spriteAsset = value; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected TMP_SpriteAsset m_spriteAsset; /// /// Determines whether or not the sprite color is multiplies by the vertex color of the text. /// public bool tintAllSprites { get { return m_tintAllSprites; } set { if (m_tintAllSprites == value) return; m_tintAllSprites = value; m_havePropertiesChanged = true; SetVerticesDirty(); } } [SerializeField] protected bool m_tintAllSprites; protected bool m_tintSprite; protected Color32 m_spriteColor; /// /// This overrides the color tags forcing the vertex colors to be the default font color. /// public bool overrideColorTags { get { return m_overrideHtmlColors; } set { if (m_overrideHtmlColors == value) return; m_havePropertiesChanged = true; m_overrideHtmlColors = value; SetVerticesDirty(); } } [SerializeField] protected bool m_overrideHtmlColors = false; /// /// Sets the color of the _FaceColor property of the assigned material. Changing face color will result in an instance of the material. /// public Color32 faceColor { get { if (m_sharedMaterial == null) return m_faceColor; m_faceColor = m_sharedMaterial.GetColor(ShaderUtilities.ID_FaceColor); return m_faceColor; } set { if (m_faceColor.Compare(value)) return; SetFaceColor(value); m_havePropertiesChanged = true; m_faceColor = value; SetVerticesDirty(); SetMaterialDirty(); } } [SerializeField] protected Color32 m_faceColor = Color.white; /// /// Sets the color of the _OutlineColor property of the assigned material. Changing outline color will result in an instance of the material. /// public Color32 outlineColor { get { if (m_sharedMaterial == null) return m_outlineColor; m_outlineColor = m_sharedMaterial.GetColor(ShaderUtilities.ID_OutlineColor); return m_outlineColor; } set { if (m_outlineColor.Compare(value)) return; SetOutlineColor(value); m_havePropertiesChanged = true; m_outlineColor = value; SetVerticesDirty(); } } [SerializeField] protected Color32 m_outlineColor = Color.black; /// /// Sets the thickness of the outline of the font. Setting this value will result in an instance of the material. /// public float outlineWidth { get { if (m_sharedMaterial == null) return m_outlineWidth; m_outlineWidth = m_sharedMaterial.GetFloat(ShaderUtilities.ID_OutlineWidth); return m_outlineWidth; } set { if (m_outlineWidth == value) return; SetOutlineThickness(value); m_havePropertiesChanged = true; m_outlineWidth = value; SetVerticesDirty(); } } protected float m_outlineWidth = 0.0f; /// /// The point size of the font. /// public float fontSize { get { return m_fontSize; } set { if (m_fontSize == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_fontSize = value; if (!m_enableAutoSizing) m_fontSizeBase = m_fontSize; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_fontSize = 36; // Font Size protected float m_currentFontSize; // Temporary Font Size affected by tags [SerializeField] protected float m_fontSizeBase = 36; protected TMP_XmlTagStack m_sizeStack = new TMP_XmlTagStack(new float[16]); /// /// The scale of the current text. /// public float fontScale { get { return m_fontScale; } } /// /// Control the weight of the font if an alternative font asset is assigned for the given weight in the font asset editor. /// public int fontWeight { get { return m_fontWeight; } set { if (m_fontWeight == value) return; m_fontWeight = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected int m_fontWeight = 400; protected int m_fontWeightInternal; protected TMP_XmlTagStack m_fontWeightStack = new TMP_XmlTagStack(new int[16]); /// /// /// public float pixelsPerUnit { get { var localCanvas = canvas; if (!localCanvas) return 1; // For dynamic fonts, ensure we use one pixel per pixel on the screen. if (!font) return localCanvas.scaleFactor; // For non-dynamic fonts, calculate pixels per unit based on specified font size relative to font object's own font size. if (m_currentFontAsset == null || m_currentFontAsset.fontInfo.PointSize <= 0 || m_fontSize <= 0) return 1; return m_fontSize / m_currentFontAsset.fontInfo.PointSize; } } /// /// Enable text auto-sizing /// public bool enableAutoSizing { get { return m_enableAutoSizing; } set { if (m_enableAutoSizing == value) return; m_enableAutoSizing = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_enableAutoSizing; protected float m_maxFontSize; // Used in conjunction with auto-sizing protected float m_minFontSize; // Used in conjunction with auto-sizing /// /// Minimum point size of the font when text auto-sizing is enabled. /// public float fontSizeMin { get { return m_fontSizeMin; } set { if (m_fontSizeMin == value) return; m_fontSizeMin = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_fontSizeMin = 0; // Text Auto Sizing Min Font Size. /// /// Maximum point size of the font when text auto-sizing is enabled. /// public float fontSizeMax { get { return m_fontSizeMax; } set { if (m_fontSizeMax == value) return; m_fontSizeMax = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_fontSizeMax = 0; // Text Auto Sizing Max Font Size. /// /// The style of the text /// public FontStyles fontStyle { get { return m_fontStyle; } set { if (m_fontStyle == value) return; m_fontStyle = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected FontStyles m_fontStyle = FontStyles.Normal; protected FontStyles m_style = FontStyles.Normal; protected TMP_BasicXmlTagStack m_fontStyleStack; /// /// Property used in conjunction with padding calculation for the geometry. /// public bool isUsingBold { get { return m_isUsingBold; } } protected bool m_isUsingBold = false; // Used to ensure GetPadding & Ratios take into consideration bold characters. /// /// Text alignment options /// public TextAlignmentOptions alignment { get { return m_textAlignment; } set { if (m_textAlignment == value) return; m_havePropertiesChanged = true; m_textAlignment = value; SetVerticesDirty(); } } [SerializeField] [UnityEngine.Serialization.FormerlySerializedAs("m_lineJustification")] protected TextAlignmentOptions m_textAlignment = TextAlignmentOptions.TopLeft; protected TextAlignmentOptions m_lineJustification; protected TMP_XmlTagStack m_lineJustificationStack = new TMP_XmlTagStack(new TextAlignmentOptions[16]); protected Vector3[] m_textContainerLocalCorners = new Vector3[4]; [SerializeField] protected bool m_isAlignmentEnumConverted; /// /// Use the extents of the text geometry for alignment instead of font metrics. /// //public bool alignByGeometry //{ // get { return m_alignByGeometry; } // set { if (m_alignByGeometry == value) return; m_havePropertiesChanged = true; m_alignByGeometry = value; SetVerticesDirty(); } //} //[SerializeField] //protected bool m_alignByGeometry; /// /// The amount of additional spacing between characters. /// public float characterSpacing { get { return m_characterSpacing; } set { if (m_characterSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_characterSpacing = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_characterSpacing = 0; protected float m_cSpacing = 0; protected float m_monoSpacing = 0; /// /// The amount of additional spacing between words. /// public float wordSpacing { get { return m_wordSpacing; } set { if (m_wordSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_wordSpacing = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_wordSpacing = 0; /// /// The amount of additional spacing to add between each lines of text. /// public float lineSpacing { get { return m_lineSpacing; } set { if (m_lineSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_lineSpacing = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_lineSpacing = 0; protected float m_lineSpacingDelta = 0; // Used with Text Auto Sizing feature protected float m_lineHeight = TMP_Math.FLOAT_UNSET; // Used with the tag. /// /// The amount of potential line spacing adjustment before text auto sizing kicks in. /// public float lineSpacingAdjustment { get { return m_lineSpacingMax; } set { if (m_lineSpacingMax == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_lineSpacingMax = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_lineSpacingMax = 0; // Text Auto Sizing Max Line spacing reduction. //protected bool m_forceLineBreak; /// /// The amount of additional spacing to add between each lines of text. /// public float paragraphSpacing { get { return m_paragraphSpacing; } set { if (m_paragraphSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_paragraphSpacing = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_paragraphSpacing = 0; /// /// Percentage the width of characters can be adjusted before text auto-sizing begins to reduce the point size. /// public float characterWidthAdjustment { get { return m_charWidthMaxAdj; } set { if (m_charWidthMaxAdj == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_charWidthMaxAdj = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_charWidthMaxAdj = 0f; // Text Auto Sizing Max Character Width reduction. protected float m_charWidthAdjDelta = 0; /// /// Controls whether or not word wrapping is applied. When disabled, the text will be displayed on a single line. /// public bool enableWordWrapping { get { return m_enableWordWrapping; } set { if (m_enableWordWrapping == value) return; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_isCalculateSizeRequired = true; m_enableWordWrapping = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_enableWordWrapping = false; protected bool m_isCharacterWrappingEnabled = false; protected bool m_isNonBreakingSpace = false; protected bool m_isIgnoringAlignment; /// /// Controls the blending between using character and word spacing to fill-in the space for justified text. /// public float wordWrappingRatios { get { return m_wordWrappingRatios; } set { if (m_wordWrappingRatios == value) return; m_wordWrappingRatios = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected float m_wordWrappingRatios = 0.4f; // Controls word wrapping ratios between word or characters. /// /// /// //public bool enableAdaptiveJustification //{ // get { return m_enableAdaptiveJustification; } // set { if (m_enableAdaptiveJustification == value) return; m_enableAdaptiveJustification = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } //} //[SerializeField] //protected bool m_enableAdaptiveJustification; //protected float m_adaptiveJustificationThreshold = 10.0f; /// /// Controls the Text Overflow Mode /// public TextOverflowModes overflowMode { get { return m_overflowMode; } set { if (m_overflowMode == value) return; m_overflowMode = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected TextOverflowModes m_overflowMode = TextOverflowModes.Overflow; /// /// Indicates if the text exceeds the vertical bounds of its text container. /// public bool isTextOverflowing { get { if (m_firstOverflowCharacterIndex != -1) return true; return false; } } /// /// The first character which exceeds the vertical bounds of its text container. /// public int firstOverflowCharacterIndex { get { return m_firstOverflowCharacterIndex; } } [SerializeField] protected int m_firstOverflowCharacterIndex = -1; /// /// The linked text component used for flowing the text from one text component to another. /// public TMP_Text linkedTextComponent { get { return m_linkedTextComponent; } set { if (m_linkedTextComponent != value) { // Release previously linked text component. if (m_linkedTextComponent != null) { m_linkedTextComponent.overflowMode = TextOverflowModes.Overflow; m_linkedTextComponent.linkedTextComponent = null; m_linkedTextComponent.isLinkedTextComponent = false; } m_linkedTextComponent = value; if (m_linkedTextComponent != null) m_linkedTextComponent.isLinkedTextComponent = true; } m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected TMP_Text m_linkedTextComponent; /// /// Indicates whether this text component is linked to another. /// public bool isLinkedTextComponent { get { return m_isLinkedTextComponent; } set { m_isLinkedTextComponent = value; if (m_isLinkedTextComponent == false) m_firstVisibleCharacter = 0; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_isLinkedTextComponent; /// /// Property indicating whether the text is Truncated or using Ellipsis. /// public bool isTextTruncated { get { return m_isTextTruncated; } } [SerializeField] protected bool m_isTextTruncated; /// /// Determines if kerning is enabled or disabled. /// public bool enableKerning { get { return m_enableKerning; } set { if (m_enableKerning == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_enableKerning = value; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_enableKerning; /// /// Adds extra padding around each character. This may be necessary when the displayed text is very small to prevent clipping. /// public bool extraPadding { get { return m_enableExtraPadding; } set { if (m_enableExtraPadding == value) return; m_havePropertiesChanged = true; m_enableExtraPadding = value; UpdateMeshPadding(); /* m_isCalculateSizeRequired = true;*/ SetVerticesDirty(); /* SetLayoutDirty();*/ } } [SerializeField] protected bool m_enableExtraPadding = false; [SerializeField] protected bool checkPaddingRequired; /// /// Enables or Disables Rich Text Tags /// public bool richText { get { return m_isRichText; } set { if (m_isRichText == value) return; m_isRichText = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_isRichText = true; // Used to enable or disable Rich Text. /// /// Enables or Disables parsing of CTRL characters in input text. /// public bool parseCtrlCharacters { get { return m_parseCtrlCharacters; } set { if (m_parseCtrlCharacters == value) return; m_parseCtrlCharacters = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_parseCtrlCharacters = true; /// /// Sets the RenderQueue along with Ztest to force the text to be drawn last and on top of scene elements. /// public bool isOverlay { get { return m_isOverlay; } set { if (m_isOverlay == value) return; m_isOverlay = value; SetShaderDepth(); m_havePropertiesChanged = true; SetVerticesDirty(); } } protected bool m_isOverlay = false; /// /// Sets Perspective Correction to Zero for Orthographic Camera mode & 0.875f for Perspective Camera mode. /// public bool isOrthographic { get { return m_isOrthographic; } set { if (m_isOrthographic == value) return; m_havePropertiesChanged = true; m_isOrthographic = value; SetVerticesDirty(); } } [SerializeField] protected bool m_isOrthographic = false; /// /// Sets the culling on the shaders. Note changing this value will result in an instance of the material. /// public bool enableCulling { get { return m_isCullingEnabled; } set { if (m_isCullingEnabled == value) return; m_isCullingEnabled = value; SetCulling(); m_havePropertiesChanged = true; } } [SerializeField] protected bool m_isCullingEnabled = false; /// /// Controls whether or not the text object will be culled when using a 2D Rect Mask. /// public bool ignoreRectMaskCulling { get { return m_ignoreRectMaskCulling; } set { if (m_ignoreRectMaskCulling == value) return; m_ignoreRectMaskCulling = value; m_havePropertiesChanged = true; } } [SerializeField] protected bool m_ignoreRectMaskCulling; /// /// Forces objects that are not visible to get refreshed. /// public bool ignoreVisibility { get { return m_ignoreCulling; } set { if (m_ignoreCulling == value) return; m_havePropertiesChanged = true; m_ignoreCulling = value; } } [SerializeField] protected bool m_ignoreCulling = true; // Not implemented yet. /// /// Controls how the face and outline textures will be applied to the text object. /// public TextureMappingOptions horizontalMapping { get { return m_horizontalMapping; } set { if (m_horizontalMapping == value) return; m_havePropertiesChanged = true; m_horizontalMapping = value; SetVerticesDirty(); } } [SerializeField] protected TextureMappingOptions m_horizontalMapping = TextureMappingOptions.Character; /// /// Controls how the face and outline textures will be applied to the text object. /// public TextureMappingOptions verticalMapping { get { return m_verticalMapping; } set { if (m_verticalMapping == value) return; m_havePropertiesChanged = true; m_verticalMapping = value; SetVerticesDirty(); } } [SerializeField] protected TextureMappingOptions m_verticalMapping = TextureMappingOptions.Character; /// /// Controls the UV Offset for the various texture mapping mode on the text object. /// //public Vector2 mappingUvOffset //{ // get { return m_uvOffset; } // set { if (m_uvOffset == value) return; m_havePropertiesChanged = true; m_uvOffset = value; SetVerticesDirty(); } //} //[SerializeField] //protected Vector2 m_uvOffset = Vector2.zero; // Used to offset UV on Texturing /// /// Controls the horizontal offset of the UV of the texture mapping mode for each line of the text object. /// public float mappingUvLineOffset { get { return m_uvLineOffset; } set { if (m_uvLineOffset == value) return; m_havePropertiesChanged = true; m_uvLineOffset = value; SetVerticesDirty(); } } [SerializeField] protected float m_uvLineOffset = 0.0f; // Used for UV line offset per line /// /// Determines if the Mesh will be rendered. /// public TextRenderFlags renderMode { get { return m_renderMode; } set { if (m_renderMode == value) return; m_renderMode = value; m_havePropertiesChanged = true; } } protected TextRenderFlags m_renderMode = TextRenderFlags.Render; /// /// Determines the sorting order of the geometry of the text object. /// public VertexSortingOrder geometrySortingOrder { get { return m_geometrySortingOrder; } set { m_geometrySortingOrder = value; m_havePropertiesChanged = true; SetVerticesDirty(); } } [SerializeField] protected VertexSortingOrder m_geometrySortingOrder; /// /// The first character which should be made visible in conjunction with the Text Overflow Linked mode. /// public int firstVisibleCharacter { get { return m_firstVisibleCharacter; } set { if (m_firstVisibleCharacter == value) return; m_havePropertiesChanged = true; m_firstVisibleCharacter = value; SetVerticesDirty(); } } [SerializeField] protected int m_firstVisibleCharacter; /// /// Allows to control how many characters are visible from the input. /// public int maxVisibleCharacters { get { return m_maxVisibleCharacters; } set { if (m_maxVisibleCharacters == value) return; m_havePropertiesChanged = true; m_maxVisibleCharacters = value; SetVerticesDirty(); } } protected int m_maxVisibleCharacters = 99999; /// /// Allows to control how many words are visible from the input. /// public int maxVisibleWords { get { return m_maxVisibleWords; } set { if (m_maxVisibleWords == value) return; m_havePropertiesChanged = true; m_maxVisibleWords = value; SetVerticesDirty(); } } protected int m_maxVisibleWords = 99999; /// /// Allows control over how many lines of text are displayed. /// public int maxVisibleLines { get { return m_maxVisibleLines; } set { if (m_maxVisibleLines == value) return; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_maxVisibleLines = value; SetVerticesDirty(); } } protected int m_maxVisibleLines = 99999; /// /// Determines if the text's vertical alignment will be adjusted based on visible descender of the text. /// public bool useMaxVisibleDescender { get { return m_useMaxVisibleDescender; } set { if (m_useMaxVisibleDescender == value) return; m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); } } [SerializeField] protected bool m_useMaxVisibleDescender = true; /// /// Controls which page of text is shown /// public int pageToDisplay { get { return m_pageToDisplay; } set { if (m_pageToDisplay == value) return; m_havePropertiesChanged = true; m_pageToDisplay = value; SetVerticesDirty(); } } [SerializeField] protected int m_pageToDisplay = 1; protected bool m_isNewPage = false; /// /// The margins of the text object. /// public virtual Vector4 margin { get { return m_margin; } set { if (m_margin == value) return; m_margin = value; ComputeMarginSize(); m_havePropertiesChanged = true; SetVerticesDirty(); } } [SerializeField] protected Vector4 m_margin = new Vector4(0, 0, 0, 0); protected float m_marginLeft; protected float m_marginRight; protected float m_marginWidth; // Width of the RectTransform minus left and right margins. protected float m_marginHeight; // Height of the RectTransform minus top and bottom margins. protected float m_width = -1; /// /// Returns data about the text object which includes information about each character, word, line, link, etc. /// public TMP_TextInfo textInfo { get { return m_textInfo; } } [SerializeField] protected TMP_TextInfo m_textInfo; // Class which holds information about the Text object such as characters, lines, mesh data as well as metrics. /// /// Property tracking if any of the text properties have changed. Flag is set before the text is regenerated. /// public bool havePropertiesChanged { get { return m_havePropertiesChanged; } set { if (m_havePropertiesChanged == value) return; m_havePropertiesChanged = value; m_isInputParsingRequired = true; SetAllDirty(); } } [SerializeField] protected bool m_havePropertiesChanged; // Used to track when properties of the text object have changed. /// /// Property to handle legacy animation component. /// public bool isUsingLegacyAnimationComponent { get { return m_isUsingLegacyAnimationComponent; } set { m_isUsingLegacyAnimationComponent = value; } } [SerializeField] protected bool m_isUsingLegacyAnimationComponent; /// /// Returns are reference to the Transform /// public new Transform transform { get { if (m_transform == null) m_transform = GetComponent(); return m_transform; } } protected Transform m_transform; /// /// Returns are reference to the RectTransform /// public new RectTransform rectTransform { get { if (m_rectTransform == null) m_rectTransform = GetComponent(); return m_rectTransform; } } protected RectTransform m_rectTransform; /// /// Enables control over setting the size of the text container to match the text object. /// public virtual bool autoSizeTextContainer { get; set; } protected bool m_autoSizeTextContainer; /// /// The mesh used by the font asset and material assigned to the text object. /// public virtual Mesh mesh { get { return m_mesh; } } protected Mesh m_mesh; /// /// Determines if the geometry of the characters will be quads or volumetric (cubes). /// public bool isVolumetricText { get { return m_isVolumetricText; } set { if (m_isVolumetricText == value) return; m_havePropertiesChanged = value; m_textInfo.ResetVertexLayout(value); m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); } } [SerializeField] protected bool m_isVolumetricText; /// /// Returns the bounds of the mesh of the text object in world space. /// public Bounds bounds { get { if (m_mesh == null) return new Bounds(); return GetCompoundBounds(); } } /// /// Returns the bounds of the text of the text object. /// public Bounds textBounds { get { if (m_textInfo == null) return new Bounds(); return GetTextBounds(); } } // *** Unity Event Handling *** //[Serializable] //public class TextChangedEvent : UnityEvent { } ///// ///// Event delegate triggered when text has changed and been rendered. ///// //public TextChangedEvent onTextChanged //{ // get { return m_OnTextChanged; } // set { m_OnTextChanged = value; } //} //[SerializeField] //private TextChangedEvent m_OnTextChanged = new TextChangedEvent(); //protected void SendOnTextChanged() //{ // if (onTextChanged != null) // onTextChanged.Invoke(); //} // *** SPECIAL COMPONENTS *** /// /// Component used to control wrapping of text following some arbitrary shape. /// //public MarginShaper marginShaper //{ // get // { // if (m_marginShaper == null) m_marginShaper = GetComponent(); // return m_marginShaper; // } //} //[SerializeField] //protected MarginShaper m_marginShaper; /// /// Component used to control and animate sprites in the text object. /// protected TMP_SpriteAnimator spriteAnimator { get { if (m_spriteAnimator == null) { m_spriteAnimator = GetComponent(); if (m_spriteAnimator == null) m_spriteAnimator = gameObject.AddComponent(); } return m_spriteAnimator; } } [SerializeField] protected TMP_SpriteAnimator m_spriteAnimator; /// /// /// //public TMP_TextShaper textShaper //{ // get // { // if (m_textShaper == null) // m_textShaper = GetComponent(); // return m_textShaper; // } //} //[SerializeField] //protected TMP_TextShaper m_textShaper; // *** PROPERTIES RELATED TO UNITY LAYOUT SYSTEM *** /// /// /// public float flexibleHeight { get { return m_flexibleHeight; } } protected float m_flexibleHeight = -1f; /// /// /// public float flexibleWidth { get { return m_flexibleWidth; } } protected float m_flexibleWidth = -1f; /// /// /// public float minWidth { get { return m_minWidth; } } protected float m_minWidth; /// /// /// public float minHeight { get { return m_minHeight; } } protected float m_minHeight; /// /// /// public float maxWidth { get { return m_maxWidth; } } protected float m_maxWidth; /// /// /// public float maxHeight { get { return m_maxHeight; } } protected float m_maxHeight; /// /// /// protected LayoutElement layoutElement { get { if (m_LayoutElement == null) { m_LayoutElement = GetComponent(); } return m_LayoutElement; } } protected LayoutElement m_LayoutElement; /// /// Computed preferred width of the text object. /// public virtual float preferredWidth { get { if (!m_isPreferredWidthDirty) return m_preferredWidth; m_preferredWidth = GetPreferredWidth(); return m_preferredWidth; } } protected float m_preferredWidth; protected float m_renderedWidth; protected bool m_isPreferredWidthDirty; /// /// Computed preferred height of the text object. /// public virtual float preferredHeight { get { if (!m_isPreferredHeightDirty) return m_preferredHeight; m_preferredHeight = GetPreferredHeight(); return m_preferredHeight; } } protected float m_preferredHeight; protected float m_renderedHeight; protected bool m_isPreferredHeightDirty; protected bool m_isCalculatingPreferredValues; private int m_recursiveCount; /// /// Compute the rendered width of the text object. /// public virtual float renderedWidth { get { return GetRenderedWidth(); } } /// /// Compute the rendered height of the text object. /// public virtual float renderedHeight { get { return GetRenderedHeight(); } } /// /// /// public int layoutPriority { get { return m_layoutPriority; } } protected int m_layoutPriority = 0; protected bool m_isCalculateSizeRequired = false; protected bool m_isLayoutDirty; protected bool m_verticesAlreadyDirty; protected bool m_layoutAlreadyDirty; protected bool m_isAwake; protected bool m_isWaitingOnResourceLoad; [SerializeField] protected bool m_isInputParsingRequired = false; // Used to determine if the input text needs to be re-parsed. // Protected Fields protected enum TextInputSources { Text = 0, SetText = 1, SetCharArray = 2, String = 3 }; [SerializeField] protected TextInputSources m_inputSource; protected string old_text; // Used by SetText to determine if the text has changed. //protected float old_arg0, old_arg1, old_arg2; // Used by SetText to determine if the args have changed. protected float m_fontScale; // Scaling of the font based on Atlas true Font Size and Rendered Font Size. protected float m_fontScaleMultiplier; // Used for handling of superscript and subscript. protected char[] m_htmlTag = new char[128]; // Maximum length of rich text tag. This is preallocated to avoid GC. protected XML_TagAttribute[] m_xmlAttribute = new XML_TagAttribute[8]; protected float[] m_attributeParameterValues = new float[16]; protected float tag_LineIndent = 0; protected float tag_Indent = 0; protected TMP_XmlTagStack m_indentStack = new TMP_XmlTagStack(new float[16]); protected bool tag_NoParsing; //protected TMP_LinkInfo tag_LinkInfo = new TMP_LinkInfo(); protected bool m_isParsingText; protected Matrix4x4 m_FXMatrix; protected bool m_isFXMatrixSet; protected int[] m_char_buffer; // This array holds the characters to be processed by GenerateMesh(); private TMP_CharacterInfo[] m_internalCharacterInfo; // Used by functions to calculate preferred values. protected char[] m_input_CharArray = new char[256]; // This array hold the characters from the SetText(); private int m_charArray_Length = 0; protected int m_totalCharacterCount; // Structures used to save the state of the text layout in conjunction with line breaking / word wrapping. protected WordWrapState m_SavedWordWrapState = new WordWrapState(); protected WordWrapState m_SavedLineState = new WordWrapState(); //protected WordWrapState m_SavedAlignment = new WordWrapState (); // Fields whose state is saved in conjunction with text parsing and word wrapping. protected int m_characterCount; //protected int m_visibleCharacterCount; //protected int m_visibleSpriteCount; protected int m_firstCharacterOfLine; protected int m_firstVisibleCharacterOfLine; protected int m_lastCharacterOfLine; protected int m_lastVisibleCharacterOfLine; protected int m_lineNumber; protected int m_lineVisibleCharacterCount; protected int m_pageNumber; protected float m_maxAscender; protected float m_maxCapHeight; protected float m_maxDescender; protected float m_maxLineAscender; protected float m_maxLineDescender; protected float m_startOfLineAscender; //protected float m_maxFontScale; protected float m_lineOffset; protected Extents m_meshExtents; // Fields used for vertex colors protected Color32 m_htmlColor = new Color(255, 255, 255, 128); protected TMP_XmlTagStack m_colorStack = new TMP_XmlTagStack(new Color32[16]); protected TMP_XmlTagStack m_underlineColorStack = new TMP_XmlTagStack(new Color32[16]); protected TMP_XmlTagStack m_strikethroughColorStack = new TMP_XmlTagStack(new Color32[16]); protected TMP_XmlTagStack m_highlightColorStack = new TMP_XmlTagStack(new Color32[16]); protected TMP_ColorGradient m_colorGradientPreset; protected TMP_XmlTagStack m_colorGradientStack = new TMP_XmlTagStack(new TMP_ColorGradient[16]); protected float m_tabSpacing = 0; protected float m_spacing = 0; //protected bool IsRectTransformDriven; // STYLE TAGS protected TMP_XmlTagStack m_styleStack = new TMP_XmlTagStack(new int[16]); protected TMP_XmlTagStack m_actionStack = new TMP_XmlTagStack(new int[16]); protected float m_padding = 0; protected float m_baselineOffset; // Used for superscript and subscript. protected TMP_XmlTagStack m_baselineOffsetStack = new TMP_XmlTagStack(new float[16]); protected float m_xAdvance; // Tracks x advancement from character to character. protected TMP_TextElementType m_textElementType; protected TMP_TextElement m_cached_TextElement; // Glyph / Character information is cached into this variable which is faster than having to fetch from the Dictionary multiple times. protected TMP_Glyph m_cached_Underline_GlyphInfo; // Same as above but for the underline character which is used for Underline. protected TMP_Glyph m_cached_Ellipsis_GlyphInfo; protected TMP_SpriteAsset m_defaultSpriteAsset; protected TMP_SpriteAsset m_currentSpriteAsset; protected int m_spriteCount = 0; protected int m_spriteIndex; protected int m_spriteAnimationID; //protected TMP_XmlTagStack m_spriteAnimationStack = new TMP_XmlTagStack(new int[16]); /// /// Method which derived classes need to override to load Font Assets. /// protected virtual void LoadFontAsset() { } /// /// Function called internally when a new shared material is assigned via the fontSharedMaterial property. /// /// protected virtual void SetSharedMaterial(Material mat) { } /// /// Function called internally when a new material is assigned via the fontMaterial property. /// protected virtual Material GetMaterial(Material mat) { return null; } /// /// Function called internally when assigning a new base material. /// /// protected virtual void SetFontBaseMaterial(Material mat) { } /// /// Method which returns an array containing the materials used by the text object. /// /// protected virtual Material[] GetSharedMaterials() { return null; } /// /// /// protected virtual void SetSharedMaterials(Material[] materials) { } /// /// Method returning instances of the materials used by the text object. /// /// protected virtual Material[] GetMaterials(Material[] mats) { return null; } /// /// Method to set the materials of the text and sub text objects. /// /// //protected virtual void SetMaterials (Material[] mats) { } /// /// Function used to create an instance of the material /// /// /// protected virtual Material CreateMaterialInstance(Material source) { Material mat = new Material(source); mat.shaderKeywords = source.shaderKeywords; mat.name += " (Instance)"; return mat; } protected void SetVertexColorGradient(TMP_ColorGradient gradient) { if (gradient == null) return; m_fontColorGradient.bottomLeft = gradient.bottomLeft; m_fontColorGradient.bottomRight = gradient.bottomRight; m_fontColorGradient.topLeft = gradient.topLeft; m_fontColorGradient.topRight = gradient.topRight; SetVerticesDirty(); } /// /// Function to control the sorting of the geometry of the text object. /// protected void SetTextSortingOrder(VertexSortingOrder order) { } /// /// Function to sort the geometry of the text object in accordance to the provided order. /// /// protected void SetTextSortingOrder(int[] order) { } /// /// Function called internally to set the face color of the material. This will results in an instance of the material. /// /// protected virtual void SetFaceColor(Color32 color) { } /// /// Function called internally to set the outline color of the material. This will results in an instance of the material. /// /// protected virtual void SetOutlineColor(Color32 color) { } /// /// Function called internally to set the outline thickness property of the material. This will results in an instance of the material. /// /// protected virtual void SetOutlineThickness(float thickness) { } /// /// Set the Render Queue and ZTest mode on the current material /// protected virtual void SetShaderDepth() { } /// /// Set the culling mode on the material. /// protected virtual void SetCulling() { } /// /// Get the padding value for the currently assigned material /// /// protected virtual float GetPaddingForMaterial() { return 0; } /// /// Get the padding value for the given material /// /// protected virtual float GetPaddingForMaterial(Material mat) { return 0; } /// /// Method to return the local corners of the Text Container or RectTransform. /// /// protected virtual Vector3[] GetTextContainerLocalCorners() { return null; } // PUBLIC FUNCTIONS protected bool m_ignoreActiveState; /// /// Function to force the regeneration of the text object. /// public virtual void ForceMeshUpdate() { } /// /// Method used for resetting vertex layout when switching to and from Volumetric Text mode. /// /// //protected virtual void ResetVertexLayout() { } /// /// Function to force the regeneration of the text object. /// /// If set to true, the text object will be regenerated regardless of is active state. public virtual void ForceMeshUpdate(bool ignoreActiveState) { } /// /// Internal function used by the Text Input Field to populate TMP_TextInfo data. /// internal void SetTextInternal(string text) { m_text = text; m_renderMode = TextRenderFlags.DontRender; m_isInputParsingRequired = true; ForceMeshUpdate(); m_renderMode = TextRenderFlags.Render; } /// /// Function to force the regeneration of the text object. /// /// Flags to control which portions of the geometry gets uploaded. //public virtual void ForceMeshUpdate(TMP_VertexDataUpdateFlags flags) { } /// /// Function to update the geometry of the main and sub text objects. /// /// /// public virtual void UpdateGeometry(Mesh mesh, int index) { } /// /// Function to push the updated vertex data into the mesh and renderer. /// public virtual void UpdateVertexData(TMP_VertexDataUpdateFlags flags) { } /// /// Function to push the updated vertex data into the mesh and renderer. /// public virtual void UpdateVertexData() { } /// /// Function to push a new set of vertices to the mesh. /// /// public virtual void SetVertices(Vector3[] vertices) { } /// /// Function to be used to force recomputing of character padding when Shader / Material properties have been changed via script. /// public virtual void UpdateMeshPadding() { } /// /// /// //public virtual new void UpdateGeometry() { } /// /// Tweens the CanvasRenderer color associated with this Graphic. /// /// Target color. /// Tween duration. /// Should ignore Time.scale? /// Should also Tween the alpha channel? public override void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha) { base.CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha); InternalCrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha); } /// /// Tweens the alpha of the CanvasRenderer color associated with this Graphic. /// /// Target alpha. /// Duration of the tween in seconds. /// Should ignore Time.scale? public override void CrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale) { base.CrossFadeAlpha(alpha, duration, ignoreTimeScale); InternalCrossFadeAlpha(alpha, duration, ignoreTimeScale); } /// /// /// /// /// /// /// /// protected virtual void InternalCrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha) { } /// /// /// /// /// /// protected virtual void InternalCrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale) { } /// /// Method to parse the input text based on its source /// protected void ParseInputText() { //Debug.Log("Re-parsing Text."); ////Profiler.BeginSample("ParseInputText()"); m_isInputParsingRequired = false; switch (m_inputSource) { case TextInputSources.String: case TextInputSources.Text: StringToCharArray(m_text, ref m_char_buffer); break; case TextInputSources.SetText: SetTextArrayToCharArray(m_input_CharArray, ref m_char_buffer); break; case TextInputSources.SetCharArray: break; } SetArraySizes(m_char_buffer); ////Profiler.EndSample(); } /// /// /// /// public void SetText(string text) { SetText(text, true); } /// /// /// /// public void SetText(string text, bool syncTextInputBox) { //if (text == old_text) return; //old_text = text; m_inputSource = TextInputSources.SetCharArray; StringToCharArray(text, ref m_char_buffer); #if UNITY_EDITOR // Set the text in the Text Input Box in the Unity Editor only. // TODO: Could revise to convert to string literal if (syncTextInputBox) m_text = text; #endif m_isInputParsingRequired = true; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } /// /// Formatted string containing a pattern and a value representing the text to be rendered. /// ex. TextMeshPro.SetText ("Number is {0:1}.", 5.56f); /// /// /// String containing the pattern." /// Value is a float. public void SetText(string text, float arg0) { SetText(text, arg0, 255, 255); } /// /// Formatted string containing a pattern and a value representing the text to be rendered. /// ex. TextMeshPro.SetText ("First number is {0} and second is {1:2}.", 10, 5.756f); /// /// /// String containing the pattern." /// Value is a float. /// Value is a float. public void SetText(string text, float arg0, float arg1) { SetText(text, arg0, arg1, 255); } /// /// Formatted string containing a pattern and a value representing the text to be rendered. /// ex. TextMeshPro.SetText ("A = {0}, B = {1} and C = {2}.", 2, 5, 7); /// /// /// String containing the pattern." /// Value is a float. /// Value is a float. /// Value is a float. public void SetText(string text, float arg0, float arg1, float arg2) { // Early out if nothing has been changed from previous invocation. //if (text == old_text && arg0 == old_arg0 && arg1 == old_arg1 && arg2 == old_arg2) //{ // return; //} //old_text = text; //old_arg1 = 255; //old_arg2 = 255; int decimalPrecision = 0; int index = 0; for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c == 123) // '{' { // Check if user is requesting some decimal precision. Format is {0:2} if (text[i + 2] == 58) // ':' { decimalPrecision = text[i + 3] - 48; } switch (text[i + 1] - 48) { case 0: // 1st Arg //old_arg0 = arg0; AddFloatToCharArray(arg0, ref index, decimalPrecision); break; case 1: // 2nd Arg //old_arg1 = arg1; AddFloatToCharArray(arg1, ref index, decimalPrecision); break; case 2: // 3rd Arg //old_arg2 = arg2; AddFloatToCharArray(arg2, ref index, decimalPrecision); break; } if (text[i + 2] == 58) i += 4; else i += 2; continue; } m_input_CharArray[index] = c; index += 1; } m_input_CharArray[index] = (char)0; m_charArray_Length = index; // Set the length to where this '0' termination is. #if UNITY_EDITOR // Create new string to be displayed in the Input Text Box of the Editor Panel. m_text = new string(m_input_CharArray, 0, index); #endif m_inputSource = TextInputSources.SetText; m_isInputParsingRequired = true; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } /// /// Set the text using a StringBuilder. /// /// /// Using a StringBuilder instead of concatenating strings prevents memory pollution with temporary objects. /// /// StringBuilder with text to display. public void SetText(StringBuilder text) { m_inputSource = TextInputSources.SetCharArray; #if UNITY_EDITOR // Set the text in the Text Input Box in the Unity Editor only. m_text = text.ToString(); #endif StringBuilderToIntArray(text, ref m_char_buffer); m_isInputParsingRequired = true; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } /// /// Character array containing the text to be displayed. /// /// public void SetCharArray(char[] sourceText) { // Initialize internal character buffer if necessary if (m_char_buffer == null) m_char_buffer = new int[8]; #if UNITY_EDITOR // Create new string to be displayed in the Input Text Box of the Editor Panel. if (sourceText == null || sourceText.Length == 0) m_text = string.Empty; else m_text = new string(sourceText); #endif // Clear the Style stack. m_styleStack.Clear(); int writeIndex = 0; for (int i = 0; sourceText != null && i < sourceText.Length; i++) { if (sourceText[i] == 92 && i < sourceText.Length - 1) { switch ((int)sourceText[i + 1]) { case 110: // \n LineFeed if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)10; i += 1; writeIndex += 1; continue; case 114: // \r LineFeed if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)13; i += 1; writeIndex += 1; continue; case 116: // \t Tab if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)9; i += 1; writeIndex += 1; continue; } } // Handle inline replacement of and
tags. if (sourceText[i] == 60) { if (IsTagName(ref sourceText, "
", i)) { if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = 10; ; writeIndex += 1; i += 3; continue; } else if (IsTagName(ref sourceText, "", i)) { ReplaceClosingStyleTag(ref sourceText, i, ref m_char_buffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = sourceText[i]; writeIndex += 1; } if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)0; m_inputSource = TextInputSources.SetCharArray; m_isInputParsingRequired = true; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } /// /// Character array containing the text to be displayed. /// /// public void SetCharArray(char[] sourceText, int start, int length) { // Initialize internal character buffer if necessary if (m_char_buffer == null) m_char_buffer = new int[8]; #if UNITY_EDITOR // Create new string to be displayed in the Input Text Box of the Editor Panel. if (sourceText == null || sourceText.Length == 0 || length == 0) { m_text = string.Empty; start = 0; length = 0; } else { // TODO: Add potential range check on start + length relative to array size. m_text = new string(sourceText, start, length); } #endif // Clear the Style stack. m_styleStack.Clear(); int writeIndex = 0; int i = start; int end = start + length; for (; i < end; i++) { if (sourceText[i] == 92 && i < length - 1) { switch ((int)sourceText[i + 1]) { case 110: // \n LineFeed if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)10; i += 1; writeIndex += 1; continue; case 114: // \r LineFeed if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)13; i += 1; writeIndex += 1; continue; case 116: // \t Tab if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)9; i += 1; writeIndex += 1; continue; } } // Handle inline replacement of and
tags. if (sourceText[i] == 60) { if (IsTagName(ref sourceText, "
", i)) { if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = 10; ; writeIndex += 1; i += 3; continue; } else if (IsTagName(ref sourceText, "", i)) { ReplaceClosingStyleTag(ref sourceText, i, ref m_char_buffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = sourceText[i]; writeIndex += 1; } if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)0; m_inputSource = TextInputSources.SetCharArray; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } /// /// Character array containing the text to be displayed. /// /// public void SetCharArray(int[] sourceText, int start, int length) { // Initialize internal character buffer if necessary if (m_char_buffer == null) m_char_buffer = new int[8]; #if UNITY_EDITOR // Create new string to be displayed in the Input Text Box of the Editor Panel. if (sourceText == null || sourceText.Length == 0 || length == 0) { m_text = string.Empty; start = 0; length = 0; } else { m_text = sourceText.IntToString(start, length); } #endif // Clear the Style stack. m_styleStack.Clear(); int writeIndex = 0; int end = start + length; for (int i = start; i < end; i++) { if (sourceText[i] == 92 && i < length - 1) { switch ((int)sourceText[i + 1]) { case 110: // \n LineFeed if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)10; i += 1; writeIndex += 1; continue; case 114: // \r LineFeed if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)13; i += 1; writeIndex += 1; continue; case 116: // \t Tab if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)9; i += 1; writeIndex += 1; continue; } } // Handle inline replacement of and
tags. if (sourceText[i] == 60) { if (IsTagName(ref sourceText, "
", i)) { if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = 10; ; writeIndex += 1; i += 3; continue; } else if (IsTagName(ref sourceText, "", i)) { ReplaceClosingStyleTag(ref sourceText, i, ref m_char_buffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = sourceText[i]; writeIndex += 1; } if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer); m_char_buffer[writeIndex] = (char)0; m_inputSource = TextInputSources.SetCharArray; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); } /// /// Copies Content of formatted SetText() to charBuffer. /// /// /// protected void SetTextArrayToCharArray(char[] sourceText, ref int[] charBuffer) { //Debug.Log("SetText Array to Char called."); if (sourceText == null || m_charArray_Length == 0) return; if (charBuffer == null) charBuffer = new int[8]; // Clear the Style stack. m_styleStack.Clear(); int writeIndex = 0; for (int i = 0; i < m_charArray_Length; i++) { // Handle UTF-32 in the input text (string). if (char.IsHighSurrogate(sourceText[i]) && char.IsLowSurrogate(sourceText[i + 1])) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = char.ConvertToUtf32(sourceText[i], sourceText[i + 1]); i += 1; writeIndex += 1; continue; } // Handle inline replacement of and
tags. if (sourceText[i] == 60) { if (IsTagName(ref sourceText, "
", i)) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = 10; writeIndex += 1; i += 3; continue; } else if (IsTagName(ref sourceText, "", i)) { ReplaceClosingStyleTag(ref sourceText, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = sourceText[i]; writeIndex += 1; } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = 0; } /// /// Method to store the content of a string into an integer array. /// /// /// protected void StringToCharArray(string sourceText, ref int[] charBuffer) { if (sourceText == null) { charBuffer[0] = 0; return; } if (charBuffer == null) charBuffer = new int[8]; // Clear the Style stack. m_styleStack.SetDefault(0); int writeIndex = 0; for (int i = 0; i < sourceText.Length; i++) { if (m_inputSource == TextInputSources.Text && sourceText[i] == 92 && sourceText.Length > i + 1) { switch ((int)sourceText[i + 1]) { case 85: // \U00000000 for UTF-32 Unicode if (sourceText.Length > i + 9) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = GetUTF32(sourceText, i + 2); i += 9; writeIndex += 1; continue; } break; case 92: // \ escape if (!m_parseCtrlCharacters) break; if (sourceText.Length <= i + 2) break; if (writeIndex + 2 > charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = sourceText[i + 1]; charBuffer[writeIndex + 1] = sourceText[i + 2]; i += 2; writeIndex += 2; continue; case 110: // \n LineFeed if (!m_parseCtrlCharacters) break; if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)10; i += 1; writeIndex += 1; continue; case 114: // \r if (!m_parseCtrlCharacters) break; if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)13; i += 1; writeIndex += 1; continue; case 116: // \t Tab if (!m_parseCtrlCharacters) break; if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)9; i += 1; writeIndex += 1; continue; case 117: // \u0000 for UTF-16 Unicode if (sourceText.Length > i + 5) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)GetUTF16(sourceText, i + 2); i += 5; writeIndex += 1; continue; } break; } } // Handle UTF-32 in the input text (string). // Not sure this is needed // if (char.IsHighSurrogate(sourceText[i]) && char.IsLowSurrogate(sourceText[i + 1])) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = char.ConvertToUtf32(sourceText[i], sourceText[i + 1]); i += 1; writeIndex += 1; continue; } //// Handle inline replacement of and
tags. if (sourceText[i] == 60 && m_isRichText) { if (IsTagName(ref sourceText, "
", i)) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = 10; ; writeIndex += 1; i += 3; continue; } else if (IsTagName(ref sourceText, "", i)) { ReplaceClosingStyleTag(ref sourceText, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = sourceText[i]; writeIndex += 1; } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)0; } /// /// Copy contents of StringBuilder into int array. /// /// Text to copy. /// Array to store contents. protected void StringBuilderToIntArray(StringBuilder sourceText, ref int[] charBuffer) { if (sourceText == null) { charBuffer[0] = 0; return; } if (charBuffer == null) charBuffer = new int[8]; // Clear the Style stack. m_styleStack.Clear(); #if UNITY_EDITOR // Create new string to be displayed in the Input Text Box of the Editor Panel. m_text = sourceText.ToString(); #endif int writeIndex = 0; for (int i = 0; i < sourceText.Length; i++) { if (m_parseCtrlCharacters && sourceText[i] == 92 && sourceText.Length > i + 1) { switch ((int)sourceText[i + 1]) { case 85: // \U00000000 for UTF-32 Unicode if (sourceText.Length > i + 9) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = GetUTF32(sourceText, i + 2); i += 9; writeIndex += 1; continue; } break; case 92: // \ escape if (sourceText.Length <= i + 2) break; if (writeIndex + 2 > charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = sourceText[i + 1]; charBuffer[writeIndex + 1] = sourceText[i + 2]; i += 2; writeIndex += 2; continue; case 110: // \n LineFeed if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)10; i += 1; writeIndex += 1; continue; case 114: // \r if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)13; i += 1; writeIndex += 1; continue; case 116: // \t Tab if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)9; i += 1; writeIndex += 1; continue; case 117: // \u0000 for UTF-16 Unicode if (sourceText.Length > i + 5) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)GetUTF16(sourceText, i + 2); i += 5; writeIndex += 1; continue; } break; } } // Handle UTF-32 in the input text (string). if (char.IsHighSurrogate(sourceText[i]) && char.IsLowSurrogate(sourceText[i + 1])) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = char.ConvertToUtf32(sourceText[i], sourceText[i + 1]); i += 1; writeIndex += 1; continue; } // Handle inline replacement of and
tags. if (sourceText[i] == 60) { if (IsTagName(ref sourceText, "
", i)) { if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = 10; writeIndex += 1; i += 3; continue; } else if (IsTagName(ref sourceText, "", i)) { ReplaceClosingStyleTag(ref sourceText, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = sourceText[i]; writeIndex += 1; } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = (char)0; } /// /// Method to handle inline replacement of style tag by opening style definition. /// /// /// /// /// /// /// bool ReplaceOpeningStyleTag(ref string sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex) { // Validate ", i)) { ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to handle inline replacement of style tag by opening style definition. /// /// /// /// /// /// /// bool ReplaceOpeningStyleTag(ref int[] sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex) { // Validate ", i)) { ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to handle inline replacement of style tag by opening style definition. /// /// /// /// /// /// /// bool ReplaceOpeningStyleTag(ref char[] sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex) { // Validate ", i)) { ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to handle inline replacement of style tag by opening style definition. /// /// /// /// /// /// /// bool ReplaceOpeningStyleTag(ref StringBuilder sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex) { // Validate ", i)) { ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to handle inline replacement of style tag by closing style definition. /// /// /// /// /// /// bool ReplaceClosingStyleTag(ref string sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex) { // Get style from the Style Stack int hashCode = m_styleStack.CurrentItem(); TMP_Style style = TMP_StyleSheet.GetStyle(hashCode); m_styleStack.Remove(); // Return if we don't have a valid style. if (style == null) return false; int styleLength = style.styleClosingTagArray.Length; // Replace ", i)) { ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to handle inline replacement of style tag by closing style definition. /// /// /// /// /// /// bool ReplaceClosingStyleTag(ref int[] sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex) { // Get style from the Style Stack int hashCode = m_styleStack.CurrentItem(); TMP_Style style = TMP_StyleSheet.GetStyle(hashCode); m_styleStack.Remove(); // Return if we don't have a valid style. if (style == null) return false; int styleLength = style.styleClosingTagArray.Length; // Replace ", i)) { ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to handle inline replacement of style tag by closing style definition. /// /// /// /// /// /// bool ReplaceClosingStyleTag(ref char[] sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex) { // Get style from the Style Stack int hashCode = m_styleStack.CurrentItem(); TMP_Style style = TMP_StyleSheet.GetStyle(hashCode); m_styleStack.Remove(); // Return if we don't have a valid style. if (style == null) return false; int styleLength = style.styleClosingTagArray.Length; // Replace ", i)) { ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to handle inline replacement of style tag by closing style definition. /// /// /// /// /// /// bool ReplaceClosingStyleTag(ref StringBuilder sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex) { // Get style from the Style Stack int hashCode = m_styleStack.CurrentItem(); TMP_Style style = TMP_StyleSheet.GetStyle(hashCode); m_styleStack.Remove(); // Return if we don't have a valid style. if (style == null) return false; int styleLength = style.styleClosingTagArray.Length; // Replace ", i)) { ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex); // Strip even if style is invalid. i += 7; continue; } } if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer); charBuffer[writeIndex] = c; writeIndex += 1; } return true; } /// /// Method to check for a matching rich text tag. /// /// /// /// /// bool IsTagName (ref string text, string tag, int index) { if (text.Length < index + tag.Length) return false; for (int i = 0; i < tag.Length; i++) { if (TMP_TextUtilities.ToUpperFast(text[index + i]) != tag[i]) return false; } return true; } /// /// Method to check for a matching rich text tag. /// /// /// /// /// bool IsTagName(ref char[] text, string tag, int index) { if (text.Length < index + tag.Length) return false; for (int i = 0; i < tag.Length; i++) { if (TMP_TextUtilities.ToUpperFast(text[index + i]) != tag[i]) return false; } return true; } /// /// Method to check for a matching rich text tag. /// /// /// /// /// bool IsTagName(ref int[] text, string tag, int index) { if (text.Length < index + tag.Length) return false; for (int i = 0; i < tag.Length; i++) { if (TMP_TextUtilities.ToUpperFast((char)text[index + i]) != tag[i]) return false; } return true; } /// /// Method to check for a matching rich text tag. /// /// /// /// /// bool IsTagName(ref StringBuilder text, string tag, int index) { if (text.Length < index + tag.Length) return false; for (int i = 0; i < tag.Length; i++) { if (TMP_TextUtilities.ToUpperFast(text[index + i]) != tag[i]) return false; } return true; } /// /// Get Hashcode for a given tag. /// /// /// /// /// int GetTagHashCode(ref string text, int index, out int closeIndex) { int hashCode = 0; closeIndex = 0; for (int i = index; i < text.Length; i++) { // Skip quote '"' character if (text[i] == 34) continue; // Break at '>' if (text[i] == 62) { closeIndex = i; break; } hashCode = (hashCode << 5) + hashCode ^ text[i]; } return hashCode; } /// /// Get Hashcode for a given tag. /// /// /// /// /// int GetTagHashCode(ref char[] text, int index, out int closeIndex) { int hashCode = 0; closeIndex = 0; for (int i = index; i < text.Length; i++) { // Skip quote '"' character if (text[i] == 34) continue; // Break at '>' if (text[i] == 62) { closeIndex = i; break; } hashCode = (hashCode << 5) + hashCode ^ text[i]; } return hashCode; } /// /// Get Hashcode for a given tag. /// /// /// /// /// int GetTagHashCode(ref int[] text, int index, out int closeIndex) { int hashCode = 0; closeIndex = 0; for (int i = index; i < text.Length; i++) { // Skip quote '"' character if (text[i] == 34) continue; // Break at '>' if (text[i] == 62) { closeIndex = i; break; } hashCode = (hashCode << 5) + hashCode ^ text[i]; } return hashCode; } /// /// Get Hashcode for a given tag. /// /// /// /// /// int GetTagHashCode(ref StringBuilder text, int index, out int closeIndex) { int hashCode = 0; closeIndex = 0; for (int i = index; i < text.Length; i++) { // Skip quote '"' character if (text[i] == 34) continue; // Break at '>' if (text[i] == 62) { closeIndex = i; break; } hashCode = (hashCode << 5) + hashCode ^ text[i]; } return hashCode; } /// /// /// void ResizeInternalArray (ref T[] array) { int size = Mathf.NextPowerOfTwo(array.Length + 1); System.Array.Resize(ref array, size); } private readonly float[] k_Power = { 5e-1f, 5e-2f, 5e-3f, 5e-4f, 5e-5f, 5e-6f, 5e-7f, 5e-8f, 5e-9f, 5e-10f }; // Used by FormatText to enable rounding and avoid using Mathf.Pow. /// /// Function used in conjunction with SetText() /// /// /// /// protected void AddFloatToCharArray(float number, ref int index, int precision) { if (number < 0) { m_input_CharArray[index++] = '-'; number = -number; } number += k_Power[Mathf.Min(9, precision)]; int integer = (int)number; AddIntToCharArray(integer, ref index, precision); if (precision > 0) { // Add the decimal point m_input_CharArray[index++] = '.'; number -= integer; for (int p = 0; p < precision; p++) { number *= 10; int d = (int)(number); m_input_CharArray[index++] = (char)(d + 48); number -= d; } } } /// /// // Function used in conjunction with SetText() /// /// /// /// protected void AddIntToCharArray(int number, ref int index, int precision) { if (number < 0) { m_input_CharArray[index++] = '-'; number = -number; } int i = index; do { m_input_CharArray[i++] = (char)(number % 10 + 48); number /= 10; } while (number > 0); int lastIndex = i; // Reverse string while (index + 1 < i) { i -= 1; char t = m_input_CharArray[index]; m_input_CharArray[index] = m_input_CharArray[i]; m_input_CharArray[i] = t; index += 1; } index = lastIndex; } /// /// Method used to determine the number of visible characters and required buffer allocations. /// /// /// protected virtual int SetArraySizes(int[] chars) { return 0; } /// /// Method which parses the text input, does the layout of the text as well as generating the geometry. /// protected virtual void GenerateTextMesh() { } /// /// Function to Calculate the Preferred Width and Height of the text object. /// /// public Vector2 GetPreferredValues() { if (m_isInputParsingRequired || m_isTextTruncated) { m_isCalculatingPreferredValues = true; ParseInputText(); } // CALCULATE PREFERRED WIDTH float preferredWidth = GetPreferredWidth(); // CALCULATE PREFERRED HEIGHT float preferredHeight = GetPreferredHeight(); return new Vector2(preferredWidth, preferredHeight); } /// /// Function to Calculate the Preferred Width and Height of the text object given the provided width and height. /// /// public Vector2 GetPreferredValues(float width, float height) { if (m_isInputParsingRequired || m_isTextTruncated) { m_isCalculatingPreferredValues = true; ParseInputText(); } Vector2 margin = new Vector2(width, height); // CALCULATE PREFERRED WIDTH float preferredWidth = GetPreferredWidth(margin); // CALCULATE PREFERRED HEIGHT float preferredHeight = GetPreferredHeight(margin); return new Vector2(preferredWidth, preferredHeight); } /// /// Function to Calculate the Preferred Width and Height of the text object given a certain string. /// /// /// public Vector2 GetPreferredValues(string text) { m_isCalculatingPreferredValues = true; StringToCharArray(text, ref m_char_buffer); SetArraySizes(m_char_buffer); Vector2 margin = k_LargePositiveVector2; // CALCULATE PREFERRED WIDTH float preferredWidth = GetPreferredWidth(margin); // CALCULATE PREFERRED HEIGHT float preferredHeight = GetPreferredHeight(margin); return new Vector2(preferredWidth, preferredHeight); } /// /// Function to Calculate the Preferred Width and Height of the text object given a certain string and size of text container. /// /// /// public Vector2 GetPreferredValues(string text, float width, float height) { m_isCalculatingPreferredValues = true; StringToCharArray(text, ref m_char_buffer); SetArraySizes(m_char_buffer); Vector2 margin = new Vector2(width, height); // CALCULATE PREFERRED WIDTH float preferredWidth = GetPreferredWidth(margin); // CALCULATE PREFERRED HEIGHT float preferredHeight = GetPreferredHeight(margin); return new Vector2(preferredWidth, preferredHeight); } /// /// Method to calculate the preferred width of a text object. /// /// protected float GetPreferredWidth() { if (TMP_Settings.instance == null) return 0; float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize; // Reset auto sizing point size bounds m_minFontSize = m_fontSizeMin; m_maxFontSize = m_fontSizeMax; m_charWidthAdjDelta = 0; // Set Margins to Infinity Vector2 margin = k_LargePositiveVector2; if (m_isInputParsingRequired || m_isTextTruncated) { m_isCalculatingPreferredValues = true; ParseInputText(); } m_recursiveCount = 0; float preferredWidth = CalculatePreferredValues(fontSize, margin, true).x; m_isPreferredWidthDirty = false; //Debug.Log("GetPreferredWidth() Called at frame " + Time.frameCount + ". Returning width of " + preferredWidth); return preferredWidth; } /// /// Method to calculate the preferred width of a text object. /// /// /// protected float GetPreferredWidth(Vector2 margin) { float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize; // Reset auto sizing point size bounds m_minFontSize = m_fontSizeMin; m_maxFontSize = m_fontSizeMax; m_charWidthAdjDelta = 0; m_recursiveCount = 0; float preferredWidth = CalculatePreferredValues(fontSize, margin, true).x; //Debug.Log("GetPreferredWidth() Called. Returning width of " + preferredWidth); return preferredWidth; } /// /// Method to calculate the preferred height of a text object. /// /// protected float GetPreferredHeight() { if (TMP_Settings.instance == null) return 0; float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize; // Reset auto sizing point size bounds m_minFontSize = m_fontSizeMin; m_maxFontSize = m_fontSizeMax; m_charWidthAdjDelta = 0; Vector2 margin = new Vector2(m_marginWidth != 0 ? m_marginWidth : k_LargePositiveFloat, k_LargePositiveFloat); if (m_isInputParsingRequired || m_isTextTruncated) { m_isCalculatingPreferredValues = true; ParseInputText(); } m_recursiveCount = 0; float preferredHeight = CalculatePreferredValues(fontSize, margin, !m_enableAutoSizing).y; m_isPreferredHeightDirty = false; //Debug.Log("GetPreferredHeight() Called. Returning height of " + preferredHeight); return preferredHeight; } /// /// Method to calculate the preferred height of a text object. /// /// /// protected float GetPreferredHeight(Vector2 margin) { float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize; // Reset auto sizing point size bounds m_minFontSize = m_fontSizeMin; m_maxFontSize = m_fontSizeMax; m_charWidthAdjDelta = 0; m_recursiveCount = 0; float preferredHeight = CalculatePreferredValues(fontSize, margin, true).y; //Debug.Log("GetPreferredHeight() Called. Returning height of " + preferredHeight); return preferredHeight; } /// /// Method returning the rendered width and height of the text object. /// /// public Vector2 GetRenderedValues() { return GetTextBounds().size; } /// /// /// /// Should returned value only factor in visible characters and exclude those greater than maxVisibleCharacters for instance. /// public Vector2 GetRenderedValues(bool onlyVisibleCharacters) { return GetTextBounds(onlyVisibleCharacters).size; } /// /// Method returning the rendered width of the text object. /// /// protected float GetRenderedWidth() { return GetRenderedValues().x; } /// /// Method returning the rendered width of the text object. /// /// protected float GetRenderedWidth(bool onlyVisibleCharacters) { return GetRenderedValues(onlyVisibleCharacters).x; } /// /// Method returning the rendered height of the text object. /// /// protected float GetRenderedHeight() { return GetRenderedValues().y; } /// /// Method returning the rendered height of the text object. /// /// protected float GetRenderedHeight(bool onlyVisibleCharacters) { return GetRenderedValues(onlyVisibleCharacters).y; } /// /// Method to calculate the preferred width and height of the text object. /// /// protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector2 marginSize, bool ignoreTextAutoSizing) { //Debug.Log("*** CalculatePreferredValues() ***"); // ***** Frame: " + Time.frameCount); ////Profiler.BeginSample("TMP Generate Text - Phase I"); // 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.characterDictionary == null) { Debug.LogWarning("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID()); return Vector2.zero; } // Early exit if we don't have any Text to generate. if (m_char_buffer == null || m_char_buffer.Length == 0 || m_char_buffer[0] == (char)0) { return Vector2.zero; } m_currentFontAsset = m_fontAsset; m_currentMaterial = m_sharedMaterial; m_currentMaterialIndex = 0; m_materialReferenceStack.SetDefault(new MaterialReference(0, m_currentFontAsset, null, m_currentMaterial, m_padding)); // Total character count is computed when the text is parsed. int totalCharacterCount = m_totalCharacterCount; // m_VisibleCharacters.Count; if (m_internalCharacterInfo == null || totalCharacterCount > m_internalCharacterInfo.Length) { m_internalCharacterInfo = new TMP_CharacterInfo[totalCharacterCount > 1024 ? totalCharacterCount + 256 : Mathf.NextPowerOfTwo(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. float baseScale = m_fontScale = (defaultFontSize / m_fontAsset.fontInfo.PointSize * m_fontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); float currentElementScale = baseScale; m_fontScaleMultiplier = 1; m_currentFontSize = defaultFontSize; m_sizeStack.SetDefault(m_currentFontSize); float fontSizeDelta = 0; int charCode = 0; // Holds the character code of the currently being processed character. m_style = m_fontStyle; // Set the default style. m_lineJustification = m_textAlignment; // Sets the line justification mode to match editor alignment. m_lineJustificationStack.SetDefault(m_lineJustification); 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(); m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing). m_lineHeight = TMP_Math.FLOAT_UNSET; float lineGap = m_currentFontAsset.fontInfo.LineHeight - (m_currentFontAsset.fontInfo.Ascender - m_currentFontAsset.fontInfo.Descender); m_cSpacing = 0; // Amount of space added between characters as a result of the use of the tag. m_monoSpacing = 0; float lineOffsetDelta = 0; m_xAdvance = 0; // Used to track the position of each character. float maxXAdvance = 0; // Used to determine Preferred Width. 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 = 0; m_maxLineAscender = k_LargeNegativeFloat; m_maxLineDescender = k_LargePositiveFloat; m_lineNumber = 0; float marginWidth = marginSize.x; //float marginHeight = marginSize.y; m_marginLeft = 0; m_marginRight = 0; m_width = -1; // Used by Unity's Auto Layout system. float renderedWidth = 0; float renderedHeight = 0; float linebreakingWidth = 0; m_isCalculatingPreferredValues = true; // Tracking of the highest Ascender m_maxAscender = 0; m_maxDescender = 0; // Initialize struct to track states of word wrapping bool isFirstWord = true; bool isLastBreakingChar = false; WordWrapState savedLineState = new WordWrapState(); SaveWordWrappingState(ref savedLineState, 0, 0); WordWrapState savedWordWrapState = new WordWrapState(); int wrappingIndex = 0; // Counter to prevent recursive lockup when computing preferred values. m_recursiveCount += 1; int endTagIndex = 0; // Parse through Character buffer to read HTML tags and begin creating mesh. for (int i = 0; m_char_buffer[i] != 0; i++) { charCode = m_char_buffer[i]; // Parse Rich Text Tag #region Parse Rich Text Tag if (m_isRichText && charCode == 60) // '<' { m_isParsingText = true; m_textElementType = TMP_TextElementType.Character; // Check if Tag is valid. If valid, skip to the end of the validated tag. if (ValidateHtmlTag(m_char_buffer, i + 1, out endTagIndex)) { i = endTagIndex; // Continue to next character or handle the sprite element if (m_textElementType == TMP_TextElementType.Character) continue; } } 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 prev_MaterialIndex = m_currentMaterialIndex; bool isUsingAltTypeface = m_textInfo.characterInfo[m_characterCount].isUsingAlternateTypeface; m_isParsingText = false; // 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_style & 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_style & 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_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & 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 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_Sprite sprite = m_currentSpriteAsset.spriteInfoList[m_spriteIndex]; if (sprite == null) continue; // Sprites are assigned in the E000 Private Area + sprite Index if (charCode == 60) charCode = 57344 + m_spriteIndex; m_currentFontAsset = m_fontAsset; // The sprite scale calculations are based on the font asset assigned to the text object. // Sprite scale is used to determine line height // Current element scale represents a modified scale to normalize the sprite based on the font baseline to ascender. float spriteScale = (m_currentFontSize / m_fontAsset.fontInfo.PointSize * m_fontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); currentElementScale = m_fontAsset.fontInfo.Ascender / sprite.height * sprite.scale * spriteScale; m_cached_TextElement = sprite; m_internalCharacterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite; m_internalCharacterInfo[m_characterCount].scale = spriteScale; //m_internalCharacterInfo[m_characterCount].spriteAsset = m_currentSpriteAsset; //m_internalCharacterInfo[m_characterCount].fontAsset = m_currentFontAsset; //m_internalCharacterInfo[m_characterCount].materialReferenceIndex = m_currentMaterialIndex; m_currentMaterialIndex = prev_MaterialIndex; } else if (m_textElementType == TMP_TextElementType.Character) { m_cached_TextElement = m_textInfo.characterInfo[m_characterCount].textElement; if (m_cached_TextElement == null) continue; //m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset; //m_currentMaterial = m_textInfo.characterInfo[m_characterCount].material; m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex; // Re-calculate font scale as the font asset may have changed. m_fontScale = m_currentFontSize * smallCapsMultiplier / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f); currentElementScale = m_fontScale * m_fontScaleMultiplier * m_cached_TextElement.scale; m_internalCharacterInfo[m_characterCount].elementType = TMP_TextElementType.Character; } #endregion // Handle Soft Hyphen #region Handle Soft Hyphen float old_scale = currentElementScale; if (charCode == 0xAD) { currentElementScale = 0; } #endregion // Store some of the text object's information m_internalCharacterInfo[m_characterCount].character = (char)charCode; // Handle Kerning if Enabled. #region Handle Kerning GlyphValueRecord glyphAdjustments = new GlyphValueRecord(); if (m_enableKerning) { KerningPair adjustmentPair = null; if (m_characterCount < totalCharacterCount - 1) { uint nextGlyph = m_textInfo.characterInfo[m_characterCount + 1].character; KerningPairKey keyValue = new KerningPairKey((uint)charCode, nextGlyph); m_currentFontAsset.kerningDictionary.TryGetValue((int)keyValue.key, out adjustmentPair); if (adjustmentPair != null) glyphAdjustments = adjustmentPair.firstGlyphAdjustments; } if (m_characterCount >= 1) { uint previousGlyph = m_textInfo.characterInfo[m_characterCount - 1].character; KerningPairKey keyValue = new KerningPairKey(previousGlyph, (uint)charCode); m_currentFontAsset.kerningDictionary.TryGetValue((int)keyValue.key, out adjustmentPair); if (adjustmentPair != null) glyphAdjustments += adjustmentPair.secondGlyphAdjustments; } } #endregion // Initial Implementation for RTL support. #region Handle Right-to-Left //if (m_isRightToLeft) //{ // m_xAdvance -= ((m_cached_TextElement.xAdvance * bold_xAdvance_multiplier + m_characterSpacing + m_wordSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); // if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) // m_xAdvance -= m_wordSpacing * currentElementScale; //} #endregion // Handle Mono Spacing #region Handle Mono Spacing float monoAdvance = 0; if (m_monoSpacing != 0) { monoAdvance = (m_monoSpacing / 2 - (m_cached_TextElement.width / 2 + m_cached_TextElement.xOffset) * currentElementScale); m_xAdvance += monoAdvance; } #endregion // Set Padding based on selected font style #region Handle Style Padding if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold)) // Checks for any combination of Bold Style. { //style_padding = m_currentFontAsset.boldStyle * 2; bold_xAdvance_multiplier = 1 + m_currentFontAsset.boldSpacing * 0.01f; } else { //style_padding = m_currentFontAsset.normalStyle * 2; bold_xAdvance_multiplier = 1.0f; } #endregion Handle Style Padding m_internalCharacterInfo[m_characterCount].baseLine = 0 - m_lineOffset + m_baselineOffset; // Compute and save text element Ascender and maximum line Ascender. float elementAscender = m_currentFontAsset.fontInfo.Ascender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale / smallCapsMultiplier : m_internalCharacterInfo[m_characterCount].scale) + m_baselineOffset; m_internalCharacterInfo[m_characterCount].ascender = elementAscender - m_lineOffset; m_maxLineAscender = elementAscender > m_maxLineAscender ? elementAscender : m_maxLineAscender; // Compute and save text element Descender and maximum line Descender. float elementDescender = m_currentFontAsset.fontInfo.Descender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale / smallCapsMultiplier: m_internalCharacterInfo[m_characterCount].scale) + m_baselineOffset; float elementDescenderII = m_internalCharacterInfo[m_characterCount].descender = elementDescender - m_lineOffset; m_maxLineDescender = elementDescender < m_maxLineDescender ? elementDescender : m_maxLineDescender; // Adjust maxLineAscender and maxLineDescender if style is superscript or subscript if ((m_style & FontStyles.Subscript) == FontStyles.Subscript || (m_style & FontStyles.Superscript) == FontStyles.Superscript) { float baseAscender = (elementAscender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize; elementAscender = m_maxLineAscender; m_maxLineAscender = baseAscender > m_maxLineAscender ? baseAscender : m_maxLineAscender; float baseDescender = (elementDescender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize; elementDescender = m_maxLineDescender; m_maxLineDescender = baseDescender < m_maxLineDescender ? baseDescender : m_maxLineDescender; } if (m_lineNumber == 0) m_maxAscender = m_maxAscender > elementAscender ? m_maxAscender : elementAscender; //if (m_lineOffset == 0) pageAscender = pageAscender > elementAscender ? pageAscender : elementAscender; // Setup Mesh for visible text elements. ie. not a SPACE / LINEFEED / CARRIAGE RETURN. #region Handle Visible Characters if (charCode == 9 || charCode == 0xA0 || charCode == 0x2007 || (!char.IsWhiteSpace((char)charCode) && charCode != 0x200B) || m_textElementType == TMP_TextElementType.Sprite) { // Check if Character exceeds the width of the Text Container #region Handle Line Breaking, Text Auto-Sizing and Horizontal Overflow float width = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - m_marginLeft - m_marginRight, m_width) : marginWidth + 0.0001f - m_marginLeft - m_marginRight; bool isJustifiedOrFlush = ((_HorizontalAlignmentOptions)m_lineJustification & _HorizontalAlignmentOptions.Flush) == _HorizontalAlignmentOptions.Flush || ((_HorizontalAlignmentOptions)m_lineJustification & _HorizontalAlignmentOptions.Justified) == _HorizontalAlignmentOptions.Justified; // Calculate the line breaking width of the text. linebreakingWidth = m_xAdvance + m_cached_TextElement.xAdvance * (1 - m_charWidthAdjDelta) * (charCode != 0xAD ? currentElementScale : old_scale); // Check if Character exceeds the width of the Text Container if (linebreakingWidth > width * (isJustifiedOrFlush ? 1.05f : 1.0f)) { // Word Wrapping #region Handle Word Wrapping if (enableWordWrapping && m_characterCount != m_firstCharacterOfLine) { // Check if word wrapping is still possible #region Line Breaking Check if (wrappingIndex == savedWordWrapState.previous_WordBreak || isFirstWord) { // Word wrapping is no longer possible. Shrink size of text if auto-sizing is enabled. #region Text Auto-Sizing if (ignoreTextAutoSizing == false && m_currentFontSize > m_fontSizeMin) { // Handle Character Width Adjustments #region Character Width Adjustments if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100) { m_recursiveCount = 0; m_charWidthAdjDelta += 0.01f; return CalculatePreferredValues(defaultFontSize, marginSize, false); } #endregion // Adjust Point Size m_maxFontSize = defaultFontSize; defaultFontSize -= Mathf.Max((defaultFontSize - m_minFontSize) / 2, 0.05f); defaultFontSize = (int)(Mathf.Max(defaultFontSize, m_fontSizeMin) * 20 + 0.5f) / 20f; if (m_recursiveCount > 20) return new Vector2(renderedWidth, renderedHeight); return CalculatePreferredValues(defaultFontSize, marginSize, false); } #endregion // Word wrapping is no longer possible, now breaking up individual words. if (m_isCharacterWrappingEnabled == false) { m_isCharacterWrappingEnabled = true; } else isLastBreakingChar = true; } #endregion // Restore to previously stored state of last valid (space character or linefeed) i = RestoreWordWrappingState(ref savedWordWrapState); wrappingIndex = i; // Used to detect when line length can no longer be reduced. // Handling for Soft Hyphen if (m_char_buffer[i] == 0xAD) // && !m_isCharacterWrappingEnabled) // && ellipsisIndex != i && !m_isCharacterWrappingEnabled) { m_isTextTruncated = true; m_char_buffer[i] = 0x2D; return CalculatePreferredValues(defaultFontSize, marginSize, true); } // Check if Line Spacing of previous line needs to be adjusted. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET) { //Debug.Log("(1) Adjusting Line Spacing on line #" + m_lineNumber); float offsetDelta = m_maxLineAscender - m_startOfLineAscender; //AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta); m_lineOffset += offsetDelta; savedWordWrapState.lineOffset = m_lineOffset; savedWordWrapState.previousLineAscender = m_maxLineAscender; // TODO - Add check for character exceeding vertical bounds } //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_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender; m_firstCharacterOfLine = m_characterCount; // Store first character of the next line. // Compute Preferred Width & Height renderedWidth += m_xAdvance; if (m_enableWordWrapping) renderedHeight = m_maxAscender - m_maxDescender; else renderedHeight = Mathf.Max(renderedHeight, lineAscender - lineDescender); // Store the state of the line before starting on the new line. SaveWordWrappingState(ref savedLineState, i, m_characterCount - 1); m_lineNumber += 1; //isStartOfNewLine = true; // Check to make sure Array is large enough to hold a new line. //if (m_lineNumber >= m_internalTextInfo.lineInfo.Length) // ResizeLineExtents(m_lineNumber); // Apply Line Spacing based on scale of the last character of the line. if (m_lineHeight == TMP_Math.FLOAT_UNSET) { float ascender = m_internalCharacterInfo[m_characterCount].ascender - m_internalCharacterInfo[m_characterCount].baseLine; lineOffsetDelta = 0 - m_maxLineDescender + ascender + (lineGap + m_lineSpacing + m_lineSpacingDelta) * baseScale; m_lineOffset += lineOffsetDelta; m_startOfLineAscender = ascender; } else m_lineOffset += m_lineHeight + m_lineSpacing * baseScale; m_maxLineAscender = k_LargeNegativeFloat; m_maxLineDescender = k_LargePositiveFloat; m_xAdvance = 0 + tag_Indent; continue; } #endregion End Word Wrapping // Text Auto-Sizing (text exceeding Width of container. #region Handle Text Auto-Sizing if (ignoreTextAutoSizing == false && defaultFontSize > m_fontSizeMin) { // Handle Character Width Adjustments #region Character Width Adjustments if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100) { m_recursiveCount = 0; m_charWidthAdjDelta += 0.01f; return CalculatePreferredValues(defaultFontSize, marginSize, false); } #endregion // Adjust Point Size m_maxFontSize = defaultFontSize; defaultFontSize -= Mathf.Max((defaultFontSize - m_minFontSize) / 2, 0.05f); defaultFontSize = (int)(Mathf.Max(defaultFontSize, m_fontSizeMin) * 20 + 0.5f) / 20f; if (m_recursiveCount > 20) return new Vector2(renderedWidth, renderedHeight); return CalculatePreferredValues(defaultFontSize, marginSize, false); } #endregion End Text Auto-Sizing } #endregion End Check for Characters Exceeding Width of Text Container } #endregion Handle Visible Characters // Check if Line Spacing of previous line needs to be adjusted. #region Adjust Line Spacing if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET && !m_isNewPage) { //Debug.Log("Inline - Adjusting Line Spacing on line #" + m_lineNumber); //float gap = 0; // Compute gap. float offsetDelta = m_maxLineAscender - m_startOfLineAscender; //AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta); elementDescenderII -= offsetDelta; m_lineOffset += offsetDelta; m_startOfLineAscender += offsetDelta; savedWordWrapState.lineOffset = m_lineOffset; savedWordWrapState.previousLineAscender = m_startOfLineAscender; } #endregion // Check if text Exceeds the vertical bounds of the margin area. #region Check Vertical Bounds & Auto-Sizing /* if (m_maxAscender - elementDescenderII > marginHeight + 0.0001f) { // Handle Line spacing adjustments #region Line Spacing Adjustments if (m_enableAutoSizing && m_lineSpacingDelta > m_lineSpacingMax && m_lineNumber > 0) { //loopCountA = 0; //m_lineSpacingDelta -= 1; //GenerateTextMesh(); //return; } #endregion // Handle Text Auto-sizing resulting from text exceeding vertical bounds. #region Text Auto-Sizing (Text greater than vertical bounds) if (m_enableAutoSizing && m_fontSize > m_fontSizeMin) { m_maxFontSize = m_fontSize; m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f); m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f; //m_recursiveCount = 0; //if (loopCountA > 20) return; // Added to debug CalculatePreferredValues(m_fontSize, marginSize, false); return Vector2.zero; } #endregion Text Auto-Sizing } */ #endregion Check Vertical Bounds // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size. #region XAdvance, Tabulation & Stops if (charCode == 9) { float tabSize = m_currentFontAsset.fontInfo.TabWidth * 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_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; } else { m_xAdvance += ((m_cached_TextElement.xAdvance * bold_xAdvance_multiplier + m_characterSpacing + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; } #endregion Tabulation & Stops // Handle Carriage Return #region Carriage Return if (charCode == 13) { maxXAdvance = Mathf.Max(maxXAdvance, renderedWidth + m_xAdvance); renderedWidth = 0; m_xAdvance = 0 + tag_Indent; } #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 || m_characterCount == totalCharacterCount - 1) { // Check if Line Spacing of previous line needs to be adjusted. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET) { //Debug.Log("(2) Adjusting Line Spacing on line #" + m_lineNumber); float offsetDelta = m_maxLineAscender - m_startOfLineAscender; //AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta); elementDescenderII -= offsetDelta; m_lineOffset += offsetDelta; } // 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_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender; m_firstCharacterOfLine = m_characterCount + 1; // Store PreferredWidth paying attention to linefeed and last character of text. if (charCode == 10 && m_characterCount != totalCharacterCount - 1) { maxXAdvance = Mathf.Max(maxXAdvance, renderedWidth + linebreakingWidth); renderedWidth = 0; } else renderedWidth = Mathf.Max(maxXAdvance, renderedWidth + linebreakingWidth); renderedHeight = m_maxAscender - m_maxDescender; // Add new line if not last lines or character. if (charCode == 10) { // Store the state of the line before starting on the new line. SaveWordWrappingState(ref savedLineState, i, m_characterCount); // Store the state of the last Character before the new line. SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount); m_lineNumber += 1; // Apply Line Spacing if (m_lineHeight == TMP_Math.FLOAT_UNSET) { lineOffsetDelta = 0 - m_maxLineDescender + elementAscender + (lineGap + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * baseScale; m_lineOffset += lineOffsetDelta; } else m_lineOffset += m_lineHeight + (m_lineSpacing + m_paragraphSpacing) * baseScale; m_maxLineAscender = k_LargeNegativeFloat; m_maxLineDescender = k_LargePositiveFloat; m_startOfLineAscender = elementAscender; m_xAdvance = 0 + tag_LineIndent + tag_Indent; m_characterCount += 1; continue; } } #endregion Check for Linefeed or Last Character // 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) { if ((char.IsWhiteSpace((char)charCode) || charCode == 0x200B || charCode == 0x2D || charCode == 0xAD) && !m_isNonBreakingSpace && charCode != 0xA0 && 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 savedWordWrapState, i, m_characterCount); m_isCharacterWrappingEnabled = false; isFirstWord = false; } // Handling for East Asian languages else if ((charCode > 0x1100 && charCode < 0x11ff || /* Hangul Jamo */ charCode > 0x2E80 && charCode < 0x9FFF || /* CJK */ charCode > 0xA960 && charCode < 0xA97F || /* Hangul Jame Extended-A */ charCode > 0xAC00 && charCode < 0xD7FF || /* Hangul Syllables */ charCode > 0xF900 && charCode < 0xFAFF || /* CJK Compatibility Ideographs */ charCode > 0xFE30 && charCode < 0xFE4F || /* CJK Compatibility Forms */ charCode > 0xFF00 && charCode < 0xFFEF) /* CJK Halfwidth */ && !m_isNonBreakingSpace) { if (isFirstWord || isLastBreakingChar || TMP_Settings.linebreakingRules.leadingCharacters.ContainsKey(charCode) == false && (m_characterCount < totalCharacterCount - 1 && TMP_Settings.linebreakingRules.followingCharacters.ContainsKey(m_internalCharacterInfo[m_characterCount + 1].character) == false)) { SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount); m_isCharacterWrappingEnabled = false; isFirstWord = false; } } else if ((isFirstWord || m_isCharacterWrappingEnabled == true || isLastBreakingChar)) SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount); } #endregion Save Word Wrapping State 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 && ignoreTextAutoSizing == false && fontSizeDelta > 0.051f && defaultFontSize < m_fontSizeMax) { m_minFontSize = defaultFontSize; defaultFontSize += Mathf.Max((m_maxFontSize - defaultFontSize) / 2, 0.05f); defaultFontSize = (int)(Mathf.Min(defaultFontSize, m_fontSizeMax) * 20 + 0.5f) / 20f; if (m_recursiveCount > 20) return new Vector2(renderedWidth, renderedHeight); return CalculatePreferredValues(defaultFontSize, marginSize, false); } #endregion End Auto-sizing Check m_isCharacterWrappingEnabled = false; m_isCalculatingPreferredValues = false; // Adjust Preferred Width and Height to account for Margins. renderedWidth += m_margin.x > 0 ? m_margin.x : 0; renderedWidth += m_margin.z > 0 ? m_margin.z : 0; renderedHeight += m_margin.y > 0 ? m_margin.y : 0; renderedHeight += m_margin.w > 0 ? m_margin.w : 0; // Round Preferred Values to nearest 5/100. renderedWidth = (int)(renderedWidth * 100 + 1f) / 100f; renderedHeight = (int)(renderedHeight * 100 + 1f) / 100f; //Debug.Log("Preferred Values: (" + renderedWidth + ", " + renderedHeight + ") with Recursive count of " + m_recursiveCount); ////Profiler.EndSample(); return new Vector2(renderedWidth, renderedHeight); } /// /// Method returning the compound bounds of the text object and child sub objects. /// /// protected virtual Bounds GetCompoundBounds() { return new Bounds(); } /// /// Method which returns the bounds of the text object; /// /// protected Bounds GetTextBounds() { if (m_textInfo == null || m_textInfo.characterCount > m_textInfo.characterInfo.Length) return new Bounds(); Extents extent = new Extents(k_LargePositiveVector2, k_LargeNegativeVector2); for (int i = 0; i < m_textInfo.characterCount && i < m_textInfo.characterInfo.Length; i++) { if (!m_textInfo.characterInfo[i].isVisible) continue; extent.min.x = Mathf.Min(extent.min.x, m_textInfo.characterInfo[i].bottomLeft.x); extent.min.y = Mathf.Min(extent.min.y, m_textInfo.characterInfo[i].descender); extent.max.x = Mathf.Max(extent.max.x, m_textInfo.characterInfo[i].xAdvance); extent.max.y = Mathf.Max(extent.max.y, m_textInfo.characterInfo[i].ascender); } Vector2 size; size.x = extent.max.x - extent.min.x; size.y = extent.max.y - extent.min.y; Vector3 center = (extent.min + extent.max) / 2; return new Bounds(center, size); } /// /// Method which returns the bounds of the text object; /// /// /// protected Bounds GetTextBounds(bool onlyVisibleCharacters) { if (m_textInfo == null) return new Bounds(); Extents extent = new Extents(k_LargePositiveVector2, k_LargeNegativeVector2); for (int i = 0; i < m_textInfo.characterCount; i++) { if ((i > maxVisibleCharacters || m_textInfo.characterInfo[i].lineNumber > m_maxVisibleLines) && onlyVisibleCharacters) break; if (onlyVisibleCharacters && !m_textInfo.characterInfo[i].isVisible) continue; extent.min.x = Mathf.Min(extent.min.x, m_textInfo.characterInfo[i].origin); extent.min.y = Mathf.Min(extent.min.y, m_textInfo.characterInfo[i].descender); extent.max.x = Mathf.Max(extent.max.x, m_textInfo.characterInfo[i].xAdvance); extent.max.y = Mathf.Max(extent.max.y, m_textInfo.characterInfo[i].ascender); } Vector2 size; size.x = extent.max.x - extent.min.x; size.y = extent.max.y - extent.min.y; Vector2 center = (extent.min + extent.max) / 2; return new Bounds(center, size); } /// /// Method to adjust line spacing as a result of using different fonts or font point size. /// /// /// /// protected virtual void AdjustLineOffset(int startIndex, int endIndex, float offset) { } /// /// Function to increase the size of the Line Extents Array. /// /// protected void ResizeLineExtents(int size) { size = size > 1024 ? size + 256 : Mathf.NextPowerOfTwo(size + 1); TMP_LineInfo[] temp_lineInfo = new TMP_LineInfo[size]; for (int i = 0; i < size; i++) { if (i < m_textInfo.lineInfo.Length) temp_lineInfo[i] = m_textInfo.lineInfo[i]; else { temp_lineInfo[i].lineExtents.min = k_LargePositiveVector2; temp_lineInfo[i].lineExtents.max = k_LargeNegativeVector2; temp_lineInfo[i].ascender = k_LargeNegativeFloat; temp_lineInfo[i].descender = k_LargePositiveFloat; } } m_textInfo.lineInfo = temp_lineInfo; } protected static Vector2 k_LargePositiveVector2 = new Vector2(TMP_Math.INT_MAX, TMP_Math.INT_MAX); protected static Vector2 k_LargeNegativeVector2 = new Vector2(TMP_Math.INT_MIN, TMP_Math.INT_MIN); protected static float k_LargePositiveFloat = TMP_Math.FLOAT_MAX; protected static float k_LargeNegativeFloat = TMP_Math.FLOAT_MIN; protected static int k_LargePositiveInt = TMP_Math.INT_MAX; protected static int k_LargeNegativeInt = TMP_Math.INT_MIN; /// /// Function used to evaluate the length of a text string. /// /// /// public virtual TMP_TextInfo GetTextInfo(string text) { return null; } /// /// Function to force an update of the margin size. /// public virtual void ComputeMarginSize() { } /// /// Function used in conjunction with GetTextInfo to figure out Array allocations. /// /// /// //protected int GetArraySizes(int[] chars) //{ // //Debug.Log("Set Array Size called."); // //int visibleCount = 0; // //int totalCount = 0; // int tagEnd = 0; // m_totalCharacterCount = 0; // m_isUsingBold = false; // m_isParsingText = false; // //m_VisibleCharacters.Clear(); // for (int i = 0; chars[i] != 0; i++) // { // int c = chars[i]; // if (m_isRichText && c == 60) // if Char '<' // { // // Check if Tag is Valid // if (ValidateHtmlTag(chars, i + 1, out tagEnd)) // { // i = tagEnd; // //if ((m_style & FontStyles.Underline) == FontStyles.Underline) visibleCount += 3; // if ((m_style & FontStyles.Bold) == FontStyles.Bold) m_isUsingBold = true; // continue; // } // } // //if (!char.IsWhiteSpace((char)c) && c != 0x200B) // //{ // //visibleCount += 1; // //} // //m_VisibleCharacters.Add((char)c); // m_totalCharacterCount += 1; // } // return m_totalCharacterCount; //} /// /// Save the State of various variables used in the mesh creation loop in conjunction with Word Wrapping /// /// /// /// protected void SaveWordWrappingState(ref WordWrapState state, int index, int count) { // Multi Font & Material support related state.currentFontAsset = m_currentFontAsset; state.currentSpriteAsset = m_currentSpriteAsset; state.currentMaterial = m_currentMaterial; state.currentMaterialIndex = m_currentMaterialIndex; state.previous_WordBreak = index; state.total_CharacterCount = count; state.visible_CharacterCount = m_lineVisibleCharacterCount; //state.visible_CharacterCount = m_visibleCharacterCount; //state.visible_SpriteCount = m_visibleSpriteCount; state.visible_LinkCount = m_textInfo.linkCount; state.firstCharacterIndex = m_firstCharacterOfLine; state.firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine; state.lastVisibleCharIndex = m_lastVisibleCharacterOfLine; state.fontStyle = m_style; state.fontScale = m_fontScale; //state.maxFontScale = m_maxFontScale; state.fontScaleMultiplier = m_fontScaleMultiplier; state.currentFontSize = m_currentFontSize; state.xAdvance = m_xAdvance; state.maxCapHeight = m_maxCapHeight; state.maxAscender = m_maxAscender; state.maxDescender = m_maxDescender; state.maxLineAscender = m_maxLineAscender; state.maxLineDescender = m_maxLineDescender; state.previousLineAscender = m_startOfLineAscender; state.preferredWidth = m_preferredWidth; state.preferredHeight = m_preferredHeight; state.meshExtents = m_meshExtents; state.lineNumber = m_lineNumber; state.lineOffset = m_lineOffset; state.baselineOffset = m_baselineOffset; //state.alignment = m_lineJustification; state.vertexColor = m_htmlColor; state.underlineColor = m_underlineColor; state.strikethroughColor = m_strikethroughColor; state.highlightColor = m_highlightColor; state.isNonBreakingSpace = m_isNonBreakingSpace; state.tagNoParsing = tag_NoParsing; // XML Tag Stack state.basicStyleStack = m_fontStyleStack; state.colorStack = m_colorStack; state.underlineColorStack = m_underlineColorStack; state.strikethroughColorStack = m_strikethroughColorStack; state.highlightColorStack = m_highlightColorStack; state.colorGradientStack = m_colorGradientStack; state.sizeStack = m_sizeStack; state.indentStack = m_indentStack; state.fontWeightStack = m_fontWeightStack; state.styleStack = m_styleStack; state.baselineStack = m_baselineOffsetStack; state.actionStack = m_actionStack; state.materialReferenceStack = m_materialReferenceStack; state.lineJustificationStack = m_lineJustificationStack; //state.spriteAnimationStack = m_spriteAnimationStack; state.spriteAnimationID = m_spriteAnimationID; if (m_lineNumber < m_textInfo.lineInfo.Length) state.lineInfo = m_textInfo.lineInfo[m_lineNumber]; } /// /// Restore the State of various variables used in the mesh creation loop. /// /// /// protected int RestoreWordWrappingState(ref WordWrapState state) { int index = state.previous_WordBreak; // Multi Font & Material support related m_currentFontAsset = state.currentFontAsset; m_currentSpriteAsset = state.currentSpriteAsset; m_currentMaterial = state.currentMaterial; m_currentMaterialIndex = state.currentMaterialIndex; m_characterCount = state.total_CharacterCount + 1; m_lineVisibleCharacterCount = state.visible_CharacterCount; //m_visibleCharacterCount = state.visible_CharacterCount; //m_visibleSpriteCount = state.visible_SpriteCount; m_textInfo.linkCount = state.visible_LinkCount; m_firstCharacterOfLine = state.firstCharacterIndex; m_firstVisibleCharacterOfLine = state.firstVisibleCharacterIndex; m_lastVisibleCharacterOfLine = state.lastVisibleCharIndex; m_style = state.fontStyle; m_fontScale = state.fontScale; m_fontScaleMultiplier = state.fontScaleMultiplier; //m_maxFontScale = state.maxFontScale; m_currentFontSize = state.currentFontSize; m_xAdvance = state.xAdvance; m_maxCapHeight = state.maxCapHeight; m_maxAscender = state.maxAscender; m_maxDescender = state.maxDescender; m_maxLineAscender = state.maxLineAscender; m_maxLineDescender = state.maxLineDescender; m_startOfLineAscender = state.previousLineAscender; m_preferredWidth = state.preferredWidth; m_preferredHeight = state.preferredHeight; m_meshExtents = state.meshExtents; m_lineNumber = state.lineNumber; m_lineOffset = state.lineOffset; m_baselineOffset = state.baselineOffset; //m_lineJustification = state.alignment; m_htmlColor = state.vertexColor; m_underlineColor = state.underlineColor; m_strikethroughColor = state.strikethroughColor; m_highlightColor = state.highlightColor; m_isNonBreakingSpace = state.isNonBreakingSpace; tag_NoParsing = state.tagNoParsing; // XML Tag Stack m_fontStyleStack = state.basicStyleStack; m_colorStack = state.colorStack; m_underlineColorStack = state.underlineColorStack; m_strikethroughColorStack = state.strikethroughColorStack; m_highlightColorStack = state.highlightColorStack; m_colorGradientStack = state.colorGradientStack; m_sizeStack = state.sizeStack; m_indentStack = state.indentStack; m_fontWeightStack = state.fontWeightStack; m_styleStack = state.styleStack; m_baselineOffsetStack = state.baselineStack; m_actionStack = state.actionStack; m_materialReferenceStack = state.materialReferenceStack; m_lineJustificationStack = state.lineJustificationStack; //m_spriteAnimationStack = state.spriteAnimationStack; m_spriteAnimationID = state.spriteAnimationID; if (m_lineNumber < m_textInfo.lineInfo.Length) m_textInfo.lineInfo[m_lineNumber] = state.lineInfo; return index; } /// /// Store vertex information for each character. /// /// Style_padding. /// Vertex color. protected virtual void SaveGlyphVertexInfo(float padding, float style_padding, Color32 vertexColor) { // Save the Vertex Position for the Character #region Setup Mesh Vertices m_textInfo.characterInfo[m_characterCount].vertex_BL.position = m_textInfo.characterInfo[m_characterCount].bottomLeft; m_textInfo.characterInfo[m_characterCount].vertex_TL.position = m_textInfo.characterInfo[m_characterCount].topLeft; m_textInfo.characterInfo[m_characterCount].vertex_TR.position = m_textInfo.characterInfo[m_characterCount].topRight; m_textInfo.characterInfo[m_characterCount].vertex_BR.position = m_textInfo.characterInfo[m_characterCount].bottomRight; #endregion #region Setup Vertex Colors // Alpha is the lower of the vertex color or tag color alpha used. vertexColor.a = m_fontColor32.a < vertexColor.a ? (byte)(m_fontColor32.a) : (byte)(vertexColor.a); // Handle Vertex Colors & Vertex Color Gradient if (!m_enableVertexGradient) { m_textInfo.characterInfo[m_characterCount].vertex_BL.color = vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TL.color = vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TR.color = vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_BR.color = vertexColor; } else { if (!m_overrideHtmlColors && m_colorStack.index > 1) { m_textInfo.characterInfo[m_characterCount].vertex_BL.color = vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TL.color = vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TR.color = vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_BR.color = vertexColor; } else // Handle Vertex Color Gradient { // Use Vertex Color Gradient Preset (if one is assigned) if (m_fontColorGradientPreset != null) { m_textInfo.characterInfo[m_characterCount].vertex_BL.color = m_fontColorGradientPreset.bottomLeft * vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TL.color = m_fontColorGradientPreset.topLeft * vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TR.color = m_fontColorGradientPreset.topRight * vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_BR.color = m_fontColorGradientPreset.bottomRight * vertexColor; } else { m_textInfo.characterInfo[m_characterCount].vertex_BL.color = m_fontColorGradient.bottomLeft * vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TL.color = m_fontColorGradient.topLeft * vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_TR.color = m_fontColorGradient.topRight * vertexColor; m_textInfo.characterInfo[m_characterCount].vertex_BR.color = m_fontColorGradient.bottomRight * vertexColor; } } } if (m_colorGradientPreset != null) { m_textInfo.characterInfo[m_characterCount].vertex_BL.color *= m_colorGradientPreset.bottomLeft; m_textInfo.characterInfo[m_characterCount].vertex_TL.color *= m_colorGradientPreset.topLeft; m_textInfo.characterInfo[m_characterCount].vertex_TR.color *= m_colorGradientPreset.topRight; m_textInfo.characterInfo[m_characterCount].vertex_BR.color *= m_colorGradientPreset.bottomRight; } #endregion // Apply style_padding only if this is a SDF Shader. if (!m_isSDFShader) style_padding = 0; // Setup UVs for the Character #region Setup UVs FaceInfo faceInfo = m_currentFontAsset.fontInfo; Vector2 uv0; uv0.x = (m_cached_TextElement.x - padding - style_padding) / faceInfo.AtlasWidth; uv0.y = 1 - (m_cached_TextElement.y + padding + style_padding + m_cached_TextElement.height) / faceInfo.AtlasHeight; Vector2 uv1; uv1.x = uv0.x; uv1.y = 1 - (m_cached_TextElement.y - padding - style_padding) / faceInfo.AtlasHeight; Vector2 uv2; uv2.x = (m_cached_TextElement.x + padding + style_padding + m_cached_TextElement.width) / faceInfo.AtlasWidth; uv2.y = uv1.y; Vector2 uv3; uv3.x = uv2.x; uv3.y = uv0.y; //Vector2 uv0 = new Vector2((m_cached_TextElement.x - padding - style_padding) / faceInfo.AtlasWidth, 1 - (m_cached_TextElement.y + padding + style_padding + m_cached_TextElement.height) / faceInfo.AtlasHeight); // bottom left //Vector2 uv1 = new Vector2(uv0.x, 1 - (m_cached_TextElement.y - padding - style_padding) / faceInfo.AtlasHeight); // top left //Vector2 uv2 = new Vector2((m_cached_TextElement.x + padding + style_padding + m_cached_TextElement.width) / faceInfo.AtlasWidth, uv1.y); // top right //Vector2 uv3 = new Vector2(uv2.x, uv0.y); // bottom right // Store UV Information m_textInfo.characterInfo[m_characterCount].vertex_BL.uv = uv0; m_textInfo.characterInfo[m_characterCount].vertex_TL.uv = uv1; m_textInfo.characterInfo[m_characterCount].vertex_TR.uv = uv2; m_textInfo.characterInfo[m_characterCount].vertex_BR.uv = uv3; #endregion Setup UVs // Normal #region Setup Normals & Tangents //Vector3 normal = new Vector3(0, 0, -1); //m_textInfo.characterInfo[m_characterCount].vertex_BL.normal = normal; //m_textInfo.characterInfo[m_characterCount].vertex_TL.normal = normal; //m_textInfo.characterInfo[m_characterCount].vertex_TR.normal = normal; //m_textInfo.characterInfo[m_characterCount].vertex_BR.normal = normal; // Tangents //Vector4 tangent = new Vector4(-1, 0, 0, 1); //m_textInfo.characterInfo[m_characterCount].vertex_BL.tangent = tangent; //m_textInfo.characterInfo[m_characterCount].vertex_TL.tangent = tangent; //m_textInfo.characterInfo[m_characterCount].vertex_TR.tangent = tangent; //m_textInfo.characterInfo[m_characterCount].vertex_BR.tangent = tangent; #endregion end Normals & Tangents } /// /// Store vertex information for each sprite. /// /// /// /// protected virtual void SaveSpriteVertexInfo(Color32 vertexColor) { // Save the Vertex Position for the Character #region Setup Mesh Vertices m_textInfo.characterInfo[m_characterCount].vertex_BL.position = m_textInfo.characterInfo[m_characterCount].bottomLeft; m_textInfo.characterInfo[m_characterCount].vertex_TL.position = m_textInfo.characterInfo[m_characterCount].topLeft; m_textInfo.characterInfo[m_characterCount].vertex_TR.position = m_textInfo.characterInfo[m_characterCount].topRight; m_textInfo.characterInfo[m_characterCount].vertex_BR.position = m_textInfo.characterInfo[m_characterCount].bottomRight; #endregion // Vertex Color Alpha if (m_tintAllSprites) m_tintSprite = true; Color32 spriteColor = m_tintSprite ? m_spriteColor.Multiply(vertexColor) : m_spriteColor; spriteColor.a = spriteColor.a < m_fontColor32.a ? spriteColor.a = spriteColor.a < vertexColor.a ? spriteColor.a : vertexColor.a : m_fontColor32.a; Color32 c0 = spriteColor; Color32 c1 = spriteColor; Color32 c2 = spriteColor; Color32 c3 = spriteColor; if (m_enableVertexGradient) { if (m_fontColorGradientPreset != null) { c0 = m_tintSprite ? c0.Multiply(m_fontColorGradientPreset.bottomLeft) : c0; c1 = m_tintSprite ? c1.Multiply(m_fontColorGradientPreset.topLeft) : c1; c2 = m_tintSprite ? c2.Multiply(m_fontColorGradientPreset.topRight) : c2; c3 = m_tintSprite ? c3.Multiply(m_fontColorGradientPreset.bottomRight) : c3; } else { c0 = m_tintSprite ? c0.Multiply(m_fontColorGradient.bottomLeft) : c0; c1 = m_tintSprite ? c1.Multiply(m_fontColorGradient.topLeft) : c1; c2 = m_tintSprite ? c2.Multiply(m_fontColorGradient.topRight) : c2; c3 = m_tintSprite ? c3.Multiply(m_fontColorGradient.bottomRight) : c3; } } if (m_colorGradientPreset != null) { c0 = m_tintSprite ? c0.Multiply(m_colorGradientPreset.bottomLeft) : c0; c1 = m_tintSprite ? c1.Multiply(m_colorGradientPreset.topLeft) : c1; c2 = m_tintSprite ? c2.Multiply(m_colorGradientPreset.topRight) : c2; c3 = m_tintSprite ? c3.Multiply(m_colorGradientPreset.bottomRight) : c3; } m_textInfo.characterInfo[m_characterCount].vertex_BL.color = c0; m_textInfo.characterInfo[m_characterCount].vertex_TL.color = c1; m_textInfo.characterInfo[m_characterCount].vertex_TR.color = c2; m_textInfo.characterInfo[m_characterCount].vertex_BR.color = c3; // Setup UVs for the Character #region Setup UVs Vector2 uv0 = new Vector2(m_cached_TextElement.x / m_currentSpriteAsset.spriteSheet.width, m_cached_TextElement.y / m_currentSpriteAsset.spriteSheet.height); // bottom left Vector2 uv1 = new Vector2(uv0.x, (m_cached_TextElement.y + m_cached_TextElement.height) / m_currentSpriteAsset.spriteSheet.height); // top left Vector2 uv2 = new Vector2((m_cached_TextElement.x + m_cached_TextElement.width) / m_currentSpriteAsset.spriteSheet.width, uv1.y); // top right Vector2 uv3 = new Vector2(uv2.x, uv0.y); // bottom right // Store UV Information m_textInfo.characterInfo[m_characterCount].vertex_BL.uv = uv0; m_textInfo.characterInfo[m_characterCount].vertex_TL.uv = uv1; m_textInfo.characterInfo[m_characterCount].vertex_TR.uv = uv2; m_textInfo.characterInfo[m_characterCount].vertex_BR.uv = uv3; #endregion Setup UVs // Normal #region Setup Normals & Tangents //Vector3 normal = new Vector3(0, 0, -1); //m_textInfo.characterInfo[m_characterCount].vertex_BL.normal = normal; //m_textInfo.characterInfo[m_characterCount].vertex_TL.normal = normal; //m_textInfo.characterInfo[m_characterCount].vertex_TR.normal = normal; //m_textInfo.characterInfo[m_characterCount].vertex_BR.normal = normal; // Tangents //Vector4 tangent = new Vector4(-1, 0, 0, 1); //m_textInfo.characterInfo[m_characterCount].vertex_BL.tangent = tangent; //m_textInfo.characterInfo[m_characterCount].vertex_TL.tangent = tangent; //m_textInfo.characterInfo[m_characterCount].vertex_TR.tangent = tangent; //m_textInfo.characterInfo[m_characterCount].vertex_BR.tangent = tangent; #endregion end Normals & Tangents } /// /// Store vertex attributes into the appropriate TMP_MeshInfo. /// /// /// protected virtual void FillCharacterVertexBuffers(int i, int index_X4) { int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex; index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount; // Make sure buffers allocation are sufficient to hold the vertex data //if (m_textInfo.meshInfo[materialIndex].vertices.Length < index_X4 + 4) // m_textInfo.meshInfo[materialIndex].ResizeMeshInfo(Mathf.NextPowerOfTwo(index_X4 + 4)); TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo; m_textInfo.characterInfo[i].vertexIndex = index_X4; // Setup Vertices for Characters m_textInfo.meshInfo[materialIndex].vertices[0 + index_X4] = characterInfoArray[i].vertex_BL.position; m_textInfo.meshInfo[materialIndex].vertices[1 + index_X4] = characterInfoArray[i].vertex_TL.position; m_textInfo.meshInfo[materialIndex].vertices[2 + index_X4] = characterInfoArray[i].vertex_TR.position; m_textInfo.meshInfo[materialIndex].vertices[3 + index_X4] = characterInfoArray[i].vertex_BR.position; // Setup UVS0 m_textInfo.meshInfo[materialIndex].uvs0[0 + index_X4] = characterInfoArray[i].vertex_BL.uv; m_textInfo.meshInfo[materialIndex].uvs0[1 + index_X4] = characterInfoArray[i].vertex_TL.uv; m_textInfo.meshInfo[materialIndex].uvs0[2 + index_X4] = characterInfoArray[i].vertex_TR.uv; m_textInfo.meshInfo[materialIndex].uvs0[3 + index_X4] = characterInfoArray[i].vertex_BR.uv; // Setup UVS2 m_textInfo.meshInfo[materialIndex].uvs2[0 + index_X4] = characterInfoArray[i].vertex_BL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[1 + index_X4] = characterInfoArray[i].vertex_TL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[2 + index_X4] = characterInfoArray[i].vertex_TR.uv2; m_textInfo.meshInfo[materialIndex].uvs2[3 + index_X4] = characterInfoArray[i].vertex_BR.uv2; // Setup UVS4 //m_textInfo.meshInfo[0].uvs4[0 + index_X4] = characterInfoArray[i].vertex_BL.uv4; //m_textInfo.meshInfo[0].uvs4[1 + index_X4] = characterInfoArray[i].vertex_TL.uv4; //m_textInfo.meshInfo[0].uvs4[2 + index_X4] = characterInfoArray[i].vertex_TR.uv4; //m_textInfo.meshInfo[0].uvs4[3 + index_X4] = characterInfoArray[i].vertex_BR.uv4; // setup Vertex Colors m_textInfo.meshInfo[materialIndex].colors32[0 + index_X4] = characterInfoArray[i].vertex_BL.color; m_textInfo.meshInfo[materialIndex].colors32[1 + index_X4] = characterInfoArray[i].vertex_TL.color; m_textInfo.meshInfo[materialIndex].colors32[2 + index_X4] = characterInfoArray[i].vertex_TR.color; m_textInfo.meshInfo[materialIndex].colors32[3 + index_X4] = characterInfoArray[i].vertex_BR.color; m_textInfo.meshInfo[materialIndex].vertexCount = index_X4 + 4; } protected virtual void FillCharacterVertexBuffers(int i, int index_X4, bool isVolumetric) { int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex; index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount; TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo; m_textInfo.characterInfo[i].vertexIndex = index_X4; // Setup Vertices for Characters m_textInfo.meshInfo[materialIndex].vertices[0 + index_X4] = characterInfoArray[i].vertex_BL.position; m_textInfo.meshInfo[materialIndex].vertices[1 + index_X4] = characterInfoArray[i].vertex_TL.position; m_textInfo.meshInfo[materialIndex].vertices[2 + index_X4] = characterInfoArray[i].vertex_TR.position; m_textInfo.meshInfo[materialIndex].vertices[3 + index_X4] = characterInfoArray[i].vertex_BR.position; if (isVolumetric) { Vector3 depth = new Vector3(0, 0, m_fontSize * m_fontScale); m_textInfo.meshInfo[materialIndex].vertices[4 + index_X4] = characterInfoArray[i].vertex_BL.position + depth; m_textInfo.meshInfo[materialIndex].vertices[5 + index_X4] = characterInfoArray[i].vertex_TL.position + depth; m_textInfo.meshInfo[materialIndex].vertices[6 + index_X4] = characterInfoArray[i].vertex_TR.position + depth; m_textInfo.meshInfo[materialIndex].vertices[7 + index_X4] = characterInfoArray[i].vertex_BR.position + depth; } // Setup UVS0 m_textInfo.meshInfo[materialIndex].uvs0[0 + index_X4] = characterInfoArray[i].vertex_BL.uv; m_textInfo.meshInfo[materialIndex].uvs0[1 + index_X4] = characterInfoArray[i].vertex_TL.uv; m_textInfo.meshInfo[materialIndex].uvs0[2 + index_X4] = characterInfoArray[i].vertex_TR.uv; m_textInfo.meshInfo[materialIndex].uvs0[3 + index_X4] = characterInfoArray[i].vertex_BR.uv; if (isVolumetric) { m_textInfo.meshInfo[materialIndex].uvs0[4 + index_X4] = characterInfoArray[i].vertex_BL.uv; m_textInfo.meshInfo[materialIndex].uvs0[5 + index_X4] = characterInfoArray[i].vertex_TL.uv; m_textInfo.meshInfo[materialIndex].uvs0[6 + index_X4] = characterInfoArray[i].vertex_TR.uv; m_textInfo.meshInfo[materialIndex].uvs0[7 + index_X4] = characterInfoArray[i].vertex_BR.uv; } // Setup UVS2 m_textInfo.meshInfo[materialIndex].uvs2[0 + index_X4] = characterInfoArray[i].vertex_BL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[1 + index_X4] = characterInfoArray[i].vertex_TL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[2 + index_X4] = characterInfoArray[i].vertex_TR.uv2; m_textInfo.meshInfo[materialIndex].uvs2[3 + index_X4] = characterInfoArray[i].vertex_BR.uv2; if (isVolumetric) { m_textInfo.meshInfo[materialIndex].uvs2[4 + index_X4] = characterInfoArray[i].vertex_BL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[5 + index_X4] = characterInfoArray[i].vertex_TL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[6 + index_X4] = characterInfoArray[i].vertex_TR.uv2; m_textInfo.meshInfo[materialIndex].uvs2[7 + index_X4] = characterInfoArray[i].vertex_BR.uv2; } // Setup UVS4 //m_textInfo.meshInfo[0].uvs4[0 + index_X4] = characterInfoArray[i].vertex_BL.uv4; //m_textInfo.meshInfo[0].uvs4[1 + index_X4] = characterInfoArray[i].vertex_TL.uv4; //m_textInfo.meshInfo[0].uvs4[2 + index_X4] = characterInfoArray[i].vertex_TR.uv4; //m_textInfo.meshInfo[0].uvs4[3 + index_X4] = characterInfoArray[i].vertex_BR.uv4; // setup Vertex Colors m_textInfo.meshInfo[materialIndex].colors32[0 + index_X4] = characterInfoArray[i].vertex_BL.color; m_textInfo.meshInfo[materialIndex].colors32[1 + index_X4] = characterInfoArray[i].vertex_TL.color; m_textInfo.meshInfo[materialIndex].colors32[2 + index_X4] = characterInfoArray[i].vertex_TR.color; m_textInfo.meshInfo[materialIndex].colors32[3 + index_X4] = characterInfoArray[i].vertex_BR.color; if (isVolumetric) { Color32 backColor = new Color32(255, 255, 128, 255); m_textInfo.meshInfo[materialIndex].colors32[4 + index_X4] = backColor; //characterInfoArray[i].vertex_BL.color; m_textInfo.meshInfo[materialIndex].colors32[5 + index_X4] = backColor; //characterInfoArray[i].vertex_TL.color; m_textInfo.meshInfo[materialIndex].colors32[6 + index_X4] = backColor; //characterInfoArray[i].vertex_TR.color; m_textInfo.meshInfo[materialIndex].colors32[7 + index_X4] = backColor; //characterInfoArray[i].vertex_BR.color; } m_textInfo.meshInfo[materialIndex].vertexCount = index_X4 + (!isVolumetric ? 4 : 8); } /// /// Fill Vertex Buffers for Sprites /// /// /// protected virtual void FillSpriteVertexBuffers(int i, int index_X4) { int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex; index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount; TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo; m_textInfo.characterInfo[i].vertexIndex = index_X4; // Setup Vertices for Characters m_textInfo.meshInfo[materialIndex].vertices[0 + index_X4] = characterInfoArray[i].vertex_BL.position; m_textInfo.meshInfo[materialIndex].vertices[1 + index_X4] = characterInfoArray[i].vertex_TL.position; m_textInfo.meshInfo[materialIndex].vertices[2 + index_X4] = characterInfoArray[i].vertex_TR.position; m_textInfo.meshInfo[materialIndex].vertices[3 + index_X4] = characterInfoArray[i].vertex_BR.position; // Setup UVS0 m_textInfo.meshInfo[materialIndex].uvs0[0 + index_X4] = characterInfoArray[i].vertex_BL.uv; m_textInfo.meshInfo[materialIndex].uvs0[1 + index_X4] = characterInfoArray[i].vertex_TL.uv; m_textInfo.meshInfo[materialIndex].uvs0[2 + index_X4] = characterInfoArray[i].vertex_TR.uv; m_textInfo.meshInfo[materialIndex].uvs0[3 + index_X4] = characterInfoArray[i].vertex_BR.uv; // Setup UVS2 m_textInfo.meshInfo[materialIndex].uvs2[0 + index_X4] = characterInfoArray[i].vertex_BL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[1 + index_X4] = characterInfoArray[i].vertex_TL.uv2; m_textInfo.meshInfo[materialIndex].uvs2[2 + index_X4] = characterInfoArray[i].vertex_TR.uv2; m_textInfo.meshInfo[materialIndex].uvs2[3 + index_X4] = characterInfoArray[i].vertex_BR.uv2; // Setup UVS4 //m_textInfo.meshInfo[0].uvs4[0 + index_X4] = characterInfoArray[i].vertex_BL.uv4; //m_textInfo.meshInfo[0].uvs4[1 + index_X4] = characterInfoArray[i].vertex_TL.uv4; //m_textInfo.meshInfo[0].uvs4[2 + index_X4] = characterInfoArray[i].vertex_TR.uv4; //m_textInfo.meshInfo[0].uvs4[3 + index_X4] = characterInfoArray[i].vertex_BR.uv4; // setup Vertex Colors m_textInfo.meshInfo[materialIndex].colors32[0 + index_X4] = characterInfoArray[i].vertex_BL.color; m_textInfo.meshInfo[materialIndex].colors32[1 + index_X4] = characterInfoArray[i].vertex_TL.color; m_textInfo.meshInfo[materialIndex].colors32[2 + index_X4] = characterInfoArray[i].vertex_TR.color; m_textInfo.meshInfo[materialIndex].colors32[3 + index_X4] = characterInfoArray[i].vertex_BR.color; m_textInfo.meshInfo[materialIndex].vertexCount = index_X4 + 4; } /// /// Method to add the underline geometry. /// /// /// /// /// /// /// protected virtual void DrawUnderlineMesh(Vector3 start, Vector3 end, ref int index, float startScale, float endScale, float maxScale, float sdfScale, Color32 underlineColor) { if (m_cached_Underline_GlyphInfo == null) { if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Unable to add underline since the Font Asset doesn't contain the underline character.", this); return; } int verticesCount = index + 12; // Check to make sure our current mesh buffer allocations can hold these new Quads. if (verticesCount > m_textInfo.meshInfo[0].vertices.Length) { // Resize Mesh Buffers m_textInfo.meshInfo[0].ResizeMeshInfo(verticesCount / 4); } // Adjust the position of the underline based on the lowest character. This matters for subscript character. start.y = Mathf.Min(start.y, end.y); end.y = Mathf.Min(start.y, end.y); float segmentWidth = m_cached_Underline_GlyphInfo.width / 2 * maxScale; if (end.x - start.x < m_cached_Underline_GlyphInfo.width * maxScale) { segmentWidth = (end.x - start.x) / 2f; } float startPadding = m_padding * startScale / maxScale; float endPadding = m_padding * endScale / maxScale; float underlineThickness = m_cached_Underline_GlyphInfo.height; // UNDERLINE VERTICES FOR (3) LINE SEGMENTS #region UNDERLINE VERTICES Vector3[] vertices = m_textInfo.meshInfo[0].vertices; // Front Part of the Underline vertices[index + 0] = start + new Vector3(0, 0 - (underlineThickness + m_padding) * maxScale, 0); // BL vertices[index + 1] = start + new Vector3(0, m_padding * maxScale, 0); // TL vertices[index + 2] = vertices[index + 1] + new Vector3(segmentWidth, 0, 0); // TR vertices[index + 3] = vertices[index + 0] + new Vector3(segmentWidth, 0, 0); // BR // Middle Part of the Underline vertices[index + 4] = vertices[index + 3]; // BL vertices[index + 5] = vertices[index + 2]; // TL vertices[index + 6] = end + new Vector3(-segmentWidth, m_padding * maxScale, 0); // TR vertices[index + 7] = end + new Vector3(-segmentWidth, -(underlineThickness + m_padding) * maxScale, 0); // BR // End Part of the Underline vertices[index + 8] = vertices[index + 7]; // BL vertices[index + 9] = vertices[index + 6]; // TL vertices[index + 10] = end + new Vector3(0, m_padding * maxScale, 0); // TR vertices[index + 11] = end + new Vector3(0, -(underlineThickness + m_padding) * maxScale, 0); // BR #endregion // UNDERLINE UV0 #region HANDLE UV0 Vector2[] uvs0 = m_textInfo.meshInfo[0].uvs0; // Calculate UV required to setup the 3 Quads for the Underline. Vector2 uv0 = new Vector2((m_cached_Underline_GlyphInfo.x - startPadding) / m_fontAsset.fontInfo.AtlasWidth, 1 - (m_cached_Underline_GlyphInfo.y + m_padding + m_cached_Underline_GlyphInfo.height) / m_fontAsset.fontInfo.AtlasHeight); // bottom left Vector2 uv1 = new Vector2(uv0.x, 1 - (m_cached_Underline_GlyphInfo.y - m_padding) / m_fontAsset.fontInfo.AtlasHeight); // top left Vector2 uv2 = new Vector2((m_cached_Underline_GlyphInfo.x - startPadding + m_cached_Underline_GlyphInfo.width / 2) / m_fontAsset.fontInfo.AtlasWidth, uv1.y); // Mid Top Left Vector2 uv3 = new Vector2(uv2.x, uv0.y); // Mid Bottom Left Vector2 uv4 = new Vector2((m_cached_Underline_GlyphInfo.x + endPadding + m_cached_Underline_GlyphInfo.width / 2) / m_fontAsset.fontInfo.AtlasWidth, uv1.y); // Mid Top Right Vector2 uv5 = new Vector2(uv4.x, uv0.y); // Mid Bottom right Vector2 uv6 = new Vector2((m_cached_Underline_GlyphInfo.x + endPadding + m_cached_Underline_GlyphInfo.width) / m_fontAsset.fontInfo.AtlasWidth, uv1.y); // End Part - Bottom Right Vector2 uv7 = new Vector2(uv6.x, uv0.y); // End Part - Top Right // Left Part of the Underline uvs0[0 + index] = uv0; // BL uvs0[1 + index] = uv1; // TL uvs0[2 + index] = uv2; // TR uvs0[3 + index] = uv3; // BR // Middle Part of the Underline uvs0[4 + index] = new Vector2(uv2.x - uv2.x * 0.001f, uv0.y); uvs0[5 + index] = new Vector2(uv2.x - uv2.x * 0.001f, uv1.y); uvs0[6 + index] = new Vector2(uv2.x + uv2.x * 0.001f, uv1.y); uvs0[7 + index] = new Vector2(uv2.x + uv2.x * 0.001f, uv0.y); // Right Part of the Underline uvs0[8 + index] = uv5; uvs0[9 + index] = uv4; uvs0[10 + index] = uv6; uvs0[11 + index] = uv7; #endregion // UNDERLINE UV2 #region HANDLE UV2 - SDF SCALE // UV1 contains Face / Border UV layout. float min_UvX = 0; float max_UvX = (vertices[index + 2].x - start.x) / (end.x - start.x); //Calculate the xScale or how much the UV's are getting stretched on the X axis for the middle section of the underline. float xScale = Mathf.Abs(sdfScale); Vector2[] uvs2 = m_textInfo.meshInfo[0].uvs2; uvs2[0 + index] = PackUV(0, 0, xScale); uvs2[1 + index] = PackUV(0, 1, xScale); uvs2[2 + index] = PackUV(max_UvX, 1, xScale); uvs2[3 + index] = PackUV(max_UvX, 0, xScale); min_UvX = (vertices[index + 4].x - start.x) / (end.x - start.x); max_UvX = (vertices[index + 6].x - start.x) / (end.x - start.x); uvs2[4 + index] = PackUV(min_UvX, 0, xScale); uvs2[5 + index] = PackUV(min_UvX, 1, xScale); uvs2[6 + index] = PackUV(max_UvX, 1, xScale); uvs2[7 + index] = PackUV(max_UvX, 0, xScale); min_UvX = (vertices[index + 8].x - start.x) / (end.x - start.x); max_UvX = (vertices[index + 6].x - start.x) / (end.x - start.x); uvs2[8 + index] = PackUV(min_UvX, 0, xScale); uvs2[9 + index] = PackUV(min_UvX, 1, xScale); uvs2[10 + index] = PackUV(1, 1, xScale); uvs2[11 + index] = PackUV(1, 0, xScale); #endregion // UNDERLINE VERTEX COLORS #region // Alpha is the lower of the vertex color or tag color alpha used. underlineColor.a = m_fontColor32.a < underlineColor.a ? (byte)(m_fontColor32.a) : (byte)(underlineColor.a); Color32[] colors32 = m_textInfo.meshInfo[0].colors32; colors32[0 + index] = underlineColor; colors32[1 + index] = underlineColor; colors32[2 + index] = underlineColor; colors32[3 + index] = underlineColor; colors32[4 + index] = underlineColor; colors32[5 + index] = underlineColor; colors32[6 + index] = underlineColor; colors32[7 + index] = underlineColor; colors32[8 + index] = underlineColor; colors32[9 + index] = underlineColor; colors32[10 + index] = underlineColor; colors32[11 + index] = underlineColor; #endregion index += 12; } protected virtual void DrawTextHighlight(Vector3 start, Vector3 end, ref int index, Color32 highlightColor) { if (m_cached_Underline_GlyphInfo == null) { if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Unable to add underline since the Font Asset doesn't contain the underline character.", this); return; } int verticesCount = index + 4; // Check to make sure our current mesh buffer allocations can hold these new Quads. if (verticesCount > m_textInfo.meshInfo[0].vertices.Length) { // Resize Mesh Buffers m_textInfo.meshInfo[0].ResizeMeshInfo(verticesCount / 4); } // UNDERLINE VERTICES FOR (3) LINE SEGMENTS #region HIGHLIGHT VERTICES Vector3[] vertices = m_textInfo.meshInfo[0].vertices; // Front Part of the Underline vertices[index + 0] = start; // BL vertices[index + 1] = new Vector3(start.x, end.y, 0); // TL vertices[index + 2] = end; // TR vertices[index + 3] = new Vector3(end.x, start.y, 0); // BR #endregion // UNDERLINE UV0 #region HANDLE UV0 Vector2[] uvs0 = m_textInfo.meshInfo[0].uvs0; // Calculate UV required to setup the 3 Quads for the Underline. Vector2 uv0 = new Vector2((m_cached_Underline_GlyphInfo.x + m_cached_Underline_GlyphInfo.width / 2) / m_fontAsset.fontInfo.AtlasWidth, 1 - (m_cached_Underline_GlyphInfo.y + m_cached_Underline_GlyphInfo.height / 2) / m_fontAsset.fontInfo.AtlasHeight); // bottom left //Vector2 uv1 = new Vector2(uv0.x, uv0.y); // top left //Vector2 uv2 = new Vector2(uv0.x, uv0.y); // Top Right //Vector2 uv3 = new Vector2(uv2.x, uv0.y); // Bottom Right // Left Part of the Underline uvs0[0 + index] = uv0; // BL uvs0[1 + index] = uv0; // TL uvs0[2 + index] = uv0; // TR uvs0[3 + index] = uv0; // BR #endregion // UNDERLINE UV2 #region HANDLE UV2 - SDF SCALE // UV1 contains Face / Border UV layout. //float min_UvX = 0; //float max_UvX = (vertices[index + 2].x - start.x) / (end.x - start.x); ////Calculate the xScale or how much the UV's are getting stretched on the X axis for the middle section of the underline. //float xScale = 0; // Mathf.Abs(sdfScale); Vector2[] uvs2 = m_textInfo.meshInfo[0].uvs2; Vector2 customUV = new Vector2(0, 1); uvs2[0 + index] = customUV; // PackUV(-0.2f, -0.2f, xScale); uvs2[1 + index] = customUV; // PackUV(-0.2f, -0.1f, xScale); uvs2[2 + index] = customUV; // PackUV(-0.1f, -0.1f, xScale); uvs2[3 + index] = customUV; // PackUV(-0.1f, -0.2f, xScale); #endregion // HIGHLIGHT VERTEX COLORS #region // Alpha is the lower of the vertex color or tag color alpha used. highlightColor.a = m_fontColor32.a < highlightColor.a ? m_fontColor32.a : highlightColor.a; Color32[] colors32 = m_textInfo.meshInfo[0].colors32; colors32[0 + index] = highlightColor; colors32[1 + index] = highlightColor; colors32[2 + index] = highlightColor; colors32[3 + index] = highlightColor; #endregion index += 4; } /// /// Internal function used to load the default settings of text objects. /// protected void LoadDefaultSettings() { if (m_text == null || m_isWaitingOnResourceLoad) { if (TMP_Settings.autoSizeTextContainer) autoSizeTextContainer = true; else { m_rectTransform = this.rectTransform; if (GetType() == typeof(TextMeshPro)) m_rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProTextContainerSize; else m_rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProUITextContainerSize; } m_enableWordWrapping = TMP_Settings.enableWordWrapping; m_enableKerning = TMP_Settings.enableKerning; m_enableExtraPadding = TMP_Settings.enableExtraPadding; m_tintAllSprites = TMP_Settings.enableTintAllSprites; m_parseCtrlCharacters = TMP_Settings.enableParseEscapeCharacters; m_fontSize = m_fontSizeBase = TMP_Settings.defaultFontSize; m_fontSizeMin = m_fontSize * TMP_Settings.defaultTextAutoSizingMinRatio; m_fontSizeMax = m_fontSize * TMP_Settings.defaultTextAutoSizingMaxRatio; m_isAlignmentEnumConverted = true; m_isWaitingOnResourceLoad = false; } else if (m_isAlignmentEnumConverted == false) { // Convert TextAlignmentOptions enumerations. m_isAlignmentEnumConverted = true; m_textAlignment = TMP_Compatibility.ConvertTextAlignmentEnumValues(m_textAlignment); } } /// /// Method used to find and cache references to the Underline and Ellipsis characters. /// /// protected void GetSpecialCharacters(TMP_FontAsset fontAsset) { // Check & Assign Underline Character for use with the Underline tag. if (!fontAsset.characterDictionary.TryGetValue(95, out m_cached_Underline_GlyphInfo)) //95 { // Check fallback fonts // TODO } // Check & Assign Underline Character for use with the Underline tag. if (!fontAsset.characterDictionary.TryGetValue(8230, out m_cached_Ellipsis_GlyphInfo)) //95 { // Check fallback fonts // TODO } } /// /// Replace a given number of characters (tag) in the array with a new character and shift subsequent characters in the array. /// /// Array which contains the text. /// The index of where the new character will be inserted /// Length of the tag being replaced. /// The replacement character. protected void ReplaceTagWithCharacter(int[] chars, int insertionIndex, int tagLength, char c) { chars[insertionIndex] = c; for (int i = insertionIndex + tagLength; i < chars.Length; i++) { chars[i - 3] = chars[i]; } } /// /// /// /// //protected int GetMaterialReferenceForFontWeight() //{ // //bool isItalic = (m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic; // m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentFontAsset.fontWeights[0].italicTypeface.material, m_currentFontAsset.fontWeights[0].italicTypeface, m_materialReferences, m_materialReferenceIndexLookup); // return 0; //} /// /// /// /// protected TMP_FontAsset GetFontAssetForWeight(int fontWeight) { bool isItalic = (m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic; TMP_FontAsset fontAsset = null; int weightIndex = fontWeight / 100; if (isItalic) fontAsset = m_currentFontAsset.fontWeights[weightIndex].italicTypeface; else fontAsset = m_currentFontAsset.fontWeights[weightIndex].regularTypeface; return fontAsset; } /// /// Method to Enable or Disable child SubMesh objects. /// /// protected virtual void SetActiveSubMeshes(bool state) { } /// /// Destroy Sub Mesh Objects. /// protected virtual void ClearSubMeshObjects() { } /// /// Function to clear the geometry of the Primary and Sub Text objects. /// public virtual void ClearMesh() { } /// /// Function to clear the geometry of the Primary and Sub Text objects. /// public virtual void ClearMesh(bool uploadGeometry) { } /// /// Function which returns the text after it has been parsed and rich text tags removed. /// /// public virtual string GetParsedText() { if (m_textInfo == null) return string.Empty; int characterCount = m_textInfo.characterCount; // TODO - Could implement some static buffer pool shared by all instances of TMP objects. char[] buffer = new char[characterCount]; for (int i = 0; i < characterCount && i < m_textInfo.characterInfo.Length; i++) { buffer[i] = m_textInfo.characterInfo[i].character; } return new string(buffer); } /// /// Function to pack scale information in the UV2 Channel. /// /// /// /// /// //protected Vector2 PackUV(float x, float y, float scale) //{ // Vector2 output; // output.x = Mathf.Floor(x * 4095); // output.y = Mathf.Floor(y * 4095); // output.x = (output.x * 4096) + output.y; // output.y = scale; // return output; //} /// /// Function to pack scale information in the UV2 Channel. /// /// /// /// /// protected Vector2 PackUV(float x, float y, float scale) { Vector2 output; output.x = (int)(x * 511); output.y = (int)(y * 511); output.x = (output.x * 4096) + output.y; output.y = scale; return output; } /// /// /// /// /// /// protected float PackUV(float x, float y) { double x0 = (int)(x * 511); double y0 = (int)(y * 511); return (float)((x0 * 4096) + y0); } /// /// Function to pack scale information in the UV2 Channel. /// /// /// /// /// //protected Vector2 PackUV(float x, float y, float scale) //{ // Vector2 output; // output.x = Mathf.Floor(x * 4095); // output.y = Mathf.Floor(y * 4095); // return new Vector2((output.x * 4096) + output.y, scale); //} /// /// /// /// /// /// //protected float PackUV(float x, float y) //{ // x = (x % 5) / 5; // y = (y % 5) / 5; // return Mathf.Round(x * 4096) + y; //} /// /// Method to convert Hex to Int /// /// /// protected int HexToInt(char hex) { switch (hex) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case 'E': return 14; case 'F': return 15; case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; } return 15; } /// /// Convert UTF-16 Hex to Char /// /// The Unicode hex. /// The index. protected int GetUTF16(string text, int i) { int unicode = 0; unicode += HexToInt(text[i]) << 12; unicode += HexToInt(text[i + 1]) << 8; unicode += HexToInt(text[i + 2]) << 4; unicode += HexToInt(text[i + 3]); return unicode; } /// /// Convert UTF-16 Hex to Char /// /// The Unicode hex. /// The index. protected int GetUTF16(StringBuilder text, int i) { int unicode = 0; unicode += HexToInt(text[i]) << 12; unicode += HexToInt(text[i + 1]) << 8; unicode += HexToInt(text[i + 2]) << 4; unicode += HexToInt(text[i + 3]); return unicode; } /// /// Convert UTF-32 Hex to Char /// /// The Unicode hex. /// The index. protected int GetUTF32(string text, int i) { int unicode = 0; unicode += HexToInt(text[i]) << 30; unicode += HexToInt(text[i + 1]) << 24; unicode += HexToInt(text[i + 2]) << 20; unicode += HexToInt(text[i + 3]) << 16; unicode += HexToInt(text[i + 4]) << 12; unicode += HexToInt(text[i + 5]) << 8; unicode += HexToInt(text[i + 6]) << 4; unicode += HexToInt(text[i + 7]); return unicode; } /// /// Convert UTF-32 Hex to Char /// /// The Unicode hex. /// The index. protected int GetUTF32(StringBuilder text, int i) { int unicode = 0; unicode += HexToInt(text[i]) << 30; unicode += HexToInt(text[i + 1]) << 24; unicode += HexToInt(text[i + 2]) << 20; unicode += HexToInt(text[i + 3]) << 16; unicode += HexToInt(text[i + 4]) << 12; unicode += HexToInt(text[i + 5]) << 8; unicode += HexToInt(text[i + 6]) << 4; unicode += HexToInt(text[i + 7]); return unicode; } /// /// Method to convert Hex color values to Color32 /// /// /// /// protected Color32 HexCharsToColor(char[] hexChars, int tagCount) { if (tagCount == 4) { byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[1])); byte g = (byte)(HexToInt(hexChars[2]) * 16 + HexToInt(hexChars[2])); byte b = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[3])); return new Color32(r, g, b, 255); } else if (tagCount == 5) { byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[1])); byte g = (byte)(HexToInt(hexChars[2]) * 16 + HexToInt(hexChars[2])); byte b = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[3])); byte a = (byte)(HexToInt(hexChars[4]) * 16 + HexToInt(hexChars[4])); return new Color32(r, g, b, a); } else if (tagCount == 7) { byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[2])); byte g = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[4])); byte b = (byte)(HexToInt(hexChars[5]) * 16 + HexToInt(hexChars[6])); return new Color32(r, g, b, 255); } else if (tagCount == 9) { byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[2])); byte g = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[4])); byte b = (byte)(HexToInt(hexChars[5]) * 16 + HexToInt(hexChars[6])); byte a = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[8])); return new Color32(r, g, b, a); } else if (tagCount == 10) { byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[7])); byte g = (byte)(HexToInt(hexChars[8]) * 16 + HexToInt(hexChars[8])); byte b = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[9])); return new Color32(r, g, b, 255); } else if (tagCount == 11) { byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[7])); byte g = (byte)(HexToInt(hexChars[8]) * 16 + HexToInt(hexChars[8])); byte b = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[9])); byte a = (byte)(HexToInt(hexChars[10]) * 16 + HexToInt(hexChars[10])); return new Color32(r, g, b, a); } else if (tagCount == 13) { byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[8])); byte g = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[10])); byte b = (byte)(HexToInt(hexChars[11]) * 16 + HexToInt(hexChars[12])); return new Color32(r, g, b, 255); } else if (tagCount == 15) { byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[8])); byte g = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[10])); byte b = (byte)(HexToInt(hexChars[11]) * 16 + HexToInt(hexChars[12])); byte a = (byte)(HexToInt(hexChars[13]) * 16 + HexToInt(hexChars[14])); return new Color32(r, g, b, a); } return new Color32(255, 255, 255, 255); } /// /// Method to convert Hex Color values to Color32 /// /// /// /// /// protected Color32 HexCharsToColor(char[] hexChars, int startIndex, int length) { if (length == 7) { byte r = (byte)(HexToInt(hexChars[startIndex + 1]) * 16 + HexToInt(hexChars[startIndex + 2])); byte g = (byte)(HexToInt(hexChars[startIndex + 3]) * 16 + HexToInt(hexChars[startIndex + 4])); byte b = (byte)(HexToInt(hexChars[startIndex + 5]) * 16 + HexToInt(hexChars[startIndex + 6])); return new Color32(r, g, b, 255); } else if (length == 9) { byte r = (byte)(HexToInt(hexChars[startIndex + 1]) * 16 + HexToInt(hexChars[startIndex + 2])); byte g = (byte)(HexToInt(hexChars[startIndex + 3]) * 16 + HexToInt(hexChars[startIndex + 4])); byte b = (byte)(HexToInt(hexChars[startIndex + 5]) * 16 + HexToInt(hexChars[startIndex + 6])); byte a = (byte)(HexToInt(hexChars[startIndex + 7]) * 16 + HexToInt(hexChars[startIndex + 8])); return new Color32(r, g, b, a); } return s_colorWhite; } /// /// Method which returns the number of parameters used in a tag attribute and populates an array with such values. /// /// Char[] containing the tag attribute and data /// The index of the first char of the data /// The length of the data /// The number of parameters contained in the Char[] /// int GetAttributeParameters(char[] chars, int startIndex, int length, ref float[] parameters) { int endIndex = startIndex; int attributeCount = 0; while (endIndex < startIndex + length) { parameters[attributeCount] = ConvertToFloat(chars, startIndex, length, out endIndex); length -= (endIndex - startIndex) + 1; startIndex = endIndex + 1; attributeCount += 1; } return attributeCount; } /// /// Extracts a float value from char[] assuming we know the position of the start, end and decimal point. /// /// /// /// /// protected float ConvertToFloat(char[] chars, int startIndex, int length) { int lastIndex = 0; return ConvertToFloat(chars, startIndex, length, out lastIndex); } /// /// Extracts a float value from char[] given a start index and length. /// /// The Char[] containing the numerical sequence. /// The index of the start of the numerical sequence. /// The length of the numerical sequence. /// Index of the last character in the validated sequence. /// protected float ConvertToFloat(char[] chars, int startIndex, int length, out int lastIndex) { if (startIndex == 0) { lastIndex = 0; return -9999; } int endIndex = startIndex + length; bool isIntegerValue = true; float decimalPointMultiplier = 0; // Set value multiplier checking the first character to determine if we are using '+' or '-' int valueSignMultiplier = 1; if (chars[startIndex] == '+') { valueSignMultiplier = 1; startIndex += 1; } else if (chars[startIndex] == '-') { valueSignMultiplier = -1; startIndex += 1; } float value = 0; for (int i = startIndex; i < endIndex; i++) { uint c = chars[i]; if (c >= '0' && c <= '9' || c == '.') { if (c == '.') { isIntegerValue = false; decimalPointMultiplier = 0.1f; continue; } //Calculate integer and floating point value if (isIntegerValue) value = value * 10 + (c - 48) * valueSignMultiplier; else { value = value + (c - 48) * decimalPointMultiplier * valueSignMultiplier; decimalPointMultiplier *= 0.1f; } continue; } else if (c == ',') { if (i + 1 < endIndex && chars[i + 1] == ' ') lastIndex = i + 1; else lastIndex = i; return value; } } lastIndex = endIndex; return value; } /// /// Function to identify and validate the rich tag. Returns the position of the > if the tag was valid. /// /// /// /// /// protected bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex) { int tagCharCount = 0; byte attributeFlag = 0; TagUnits tagUnits = TagUnits.Pixels; TagType tagType = TagType.None; int attributeIndex = 0; m_xmlAttribute[attributeIndex].nameHashCode = 0; m_xmlAttribute[attributeIndex].valueType = TagType.None; m_xmlAttribute[attributeIndex].valueHashCode = 0; m_xmlAttribute[attributeIndex].valueStartIndex = 0; m_xmlAttribute[attributeIndex].valueLength = 0; // Clear attribute name hash codes m_xmlAttribute[1].nameHashCode = 0; m_xmlAttribute[2].nameHashCode = 0; m_xmlAttribute[3].nameHashCode = 0; m_xmlAttribute[4].nameHashCode = 0; endIndex = startIndex; bool isTagSet = false; bool isValidHtmlTag = false; for (int i = startIndex; i < chars.Length && chars[i] != 0 && tagCharCount < m_htmlTag.Length && chars[i] != 60; i++) { if (chars[i] == 62) // ASCII Code of End HTML tag '>' { isValidHtmlTag = true; endIndex = i; m_htmlTag[tagCharCount] = (char)0; break; } m_htmlTag[tagCharCount] = (char)chars[i]; tagCharCount += 1; if (attributeFlag == 1) { if (tagType == TagType.None) { // Check for attribute type if (chars[i] == 43 || chars[i] == 45 || chars[i] == 46 || (chars[i] >= '0' && chars[i] <= '9')) { tagType = TagType.NumericalValue; m_xmlAttribute[attributeIndex].valueType = TagType.NumericalValue; m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1; m_xmlAttribute[attributeIndex].valueLength += 1; } else if (chars[i] == 35) { tagType = TagType.ColorValue; m_xmlAttribute[attributeIndex].valueType = TagType.ColorValue; m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1; m_xmlAttribute[attributeIndex].valueLength += 1; } else if (chars[i] == 34) { tagType = TagType.StringValue; m_xmlAttribute[attributeIndex].valueType = TagType.StringValue; m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount; } else { tagType = TagType.StringValue; m_xmlAttribute[attributeIndex].valueType = TagType.StringValue; m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1; m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i]; m_xmlAttribute[attributeIndex].valueLength += 1; } } else { if (tagType == TagType.NumericalValue) { // Check for termination of numerical value. if (chars[i] == 112 || chars[i] == 101 || chars[i] == 37 || chars[i] == 32) { attributeFlag = 2; tagType = TagType.None; attributeIndex += 1; m_xmlAttribute[attributeIndex].nameHashCode = 0; m_xmlAttribute[attributeIndex].valueType = TagType.None; m_xmlAttribute[attributeIndex].valueHashCode = 0; m_xmlAttribute[attributeIndex].valueStartIndex = 0; m_xmlAttribute[attributeIndex].valueLength = 0; if (chars[i] == 101) tagUnits = TagUnits.FontUnits; else if (chars[i] == 37) tagUnits = TagUnits.Percentage; } else if (attributeFlag != 2) { m_xmlAttribute[attributeIndex].valueLength += 1; } } else if (tagType == TagType.ColorValue) { if (chars[i] != 32) { m_xmlAttribute[attributeIndex].valueLength += 1; } else { attributeFlag = 2; tagType = TagType.None; attributeIndex += 1; m_xmlAttribute[attributeIndex].nameHashCode = 0; m_xmlAttribute[attributeIndex].valueType = TagType.None; m_xmlAttribute[attributeIndex].valueHashCode = 0; m_xmlAttribute[attributeIndex].valueStartIndex = 0; m_xmlAttribute[attributeIndex].valueLength = 0; } } else if (tagType == TagType.StringValue) { // Compute HashCode value for the named tag. if (chars[i] != 34) { m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i]; m_xmlAttribute[attributeIndex].valueLength += 1; } else { //m_xmlAttribute[attributeIndex].valueHashCode = -1; attributeFlag = 2; tagType = TagType.None; attributeIndex += 1; m_xmlAttribute[attributeIndex].nameHashCode = 0; m_xmlAttribute[attributeIndex].valueType = TagType.None; m_xmlAttribute[attributeIndex].valueHashCode = 0; m_xmlAttribute[attributeIndex].valueStartIndex = 0; m_xmlAttribute[attributeIndex].valueLength = 0; } } } } if (chars[i] == 61) // '=' attributeFlag = 1; // Compute HashCode for the name of the attribute if (attributeFlag == 0 && chars[i] == 32) { if (isTagSet) return false; isTagSet = true; attributeFlag = 2; tagType = TagType.None; attributeIndex += 1; m_xmlAttribute[attributeIndex].nameHashCode = 0; m_xmlAttribute[attributeIndex].valueType = TagType.None; m_xmlAttribute[attributeIndex].valueHashCode = 0; m_xmlAttribute[attributeIndex].valueStartIndex = 0; m_xmlAttribute[attributeIndex].valueLength = 0; } if (attributeFlag == 0) m_xmlAttribute[attributeIndex].nameHashCode = (m_xmlAttribute[attributeIndex].nameHashCode << 3) - m_xmlAttribute[attributeIndex].nameHashCode + chars[i]; if (attributeFlag == 2 && chars[i] == 32) attributeFlag = 0; } if (!isValidHtmlTag) { return false; } //Debug.Log("Tag is [" + m_htmlTag.ArrayToString() + "]. Tag HashCode: " + m_xmlAttribute[0].nameHashCode + " Tag Value HashCode: " + m_xmlAttribute[0].valueHashCode + " Attribute 1 HashCode: " + m_xmlAttribute[1].nameHashCode + " Value HashCode: " + m_xmlAttribute[1].valueHashCode); //for (int i = 0; i < attributeIndex + 1; i++) // Debug.Log("Tag [" + i + "] with HashCode: " + m_xmlAttribute[i].nameHashCode + " has value of [" + new string(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength) + "] Numerical Value: " + ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength)); // Special handling of the no parsing tag tag if (tag_NoParsing && (m_xmlAttribute[0].nameHashCode != 53822163 && m_xmlAttribute[0].nameHashCode != 49429939)) return false; else if (m_xmlAttribute[0].nameHashCode == 53822163 || m_xmlAttribute[0].nameHashCode == 49429939) { tag_NoParsing = false; return true; } // Color <#FFF> 3 Hex values (short form) if (m_htmlTag[0] == 35 && tagCharCount == 4) { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } // Color <#FFF7> 4 Hex values with alpha (short form) else if (m_htmlTag[0] == 35 && tagCharCount == 5) { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } // Color <#FF00FF> else if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters. { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } // Color <#FF00FF00> with alpha else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters. { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } else { float value = 0; switch (m_xmlAttribute[0].nameHashCode) { case 98: // case 66: // m_style |= FontStyles.Bold; m_fontStyleStack.Add(FontStyles.Bold); m_fontWeightInternal = 700; m_fontWeightStack.Add(700); return true; case 427: // case 395: // if ((m_fontStyle & FontStyles.Bold) != FontStyles.Bold) { m_fontWeightInternal = m_fontWeightStack.Remove(); if (m_fontStyleStack.Remove(FontStyles.Bold) == 0) m_style &= ~FontStyles.Bold; } return true; case 105: // case 73: // m_style |= FontStyles.Italic; m_fontStyleStack.Add(FontStyles.Italic); return true; case 434: // case 402: // if (m_fontStyleStack.Remove(FontStyles.Italic) == 0) m_style &= ~FontStyles.Italic; return true; case 115: // case 83: // m_style |= FontStyles.Strikethrough; m_fontStyleStack.Add(FontStyles.Strikethrough); if (m_xmlAttribute[1].nameHashCode == 281955 || m_xmlAttribute[1].nameHashCode == 192323) { m_strikethroughColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength); m_strikethroughColor.a = m_htmlColor.a < m_strikethroughColor.a ? (byte)(m_htmlColor.a) : (byte)(m_strikethroughColor .a); } else m_strikethroughColor = m_htmlColor; m_strikethroughColorStack.Add(m_strikethroughColor); return true; case 444: // case 412: // if ((m_fontStyle & FontStyles.Strikethrough) != FontStyles.Strikethrough) { if (m_fontStyleStack.Remove(FontStyles.Strikethrough) == 0) m_style &= ~FontStyles.Strikethrough; } return true; case 117: // case 85: // m_style |= FontStyles.Underline; m_fontStyleStack.Add(FontStyles.Underline); if (m_xmlAttribute[1].nameHashCode == 281955 || m_xmlAttribute[1].nameHashCode == 192323) { m_underlineColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength); m_underlineColor.a = m_htmlColor.a < m_underlineColor.a ? (byte)(m_htmlColor.a) : (byte)(m_underlineColor.a); } else m_underlineColor = m_htmlColor; m_underlineColorStack.Add(m_underlineColor); return true; case 446: // case 414: // if ((m_fontStyle & FontStyles.Underline) != FontStyles.Underline) { m_underlineColor = m_underlineColorStack.Remove(); if (m_fontStyleStack.Remove(FontStyles.Underline) == 0) m_style &= ~FontStyles.Underline; } return true; case 43045: // case 30245: // m_style |= FontStyles.Highlight; m_fontStyleStack.Add(FontStyles.Highlight); m_highlightColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); m_highlightColor.a = m_htmlColor.a < m_highlightColor.a ? (byte)(m_htmlColor.a) : (byte)(m_highlightColor.a); m_highlightColorStack.Add(m_highlightColor); return true; case 155892: // case 143092: // if ((m_fontStyle & FontStyles.Highlight) != FontStyles.Highlight) { m_highlightColor = m_highlightColorStack.Remove(); if (m_fontStyleStack.Remove(FontStyles.Highlight) == 0) m_style &= ~FontStyles.Highlight; } return true; case 6552: // case 4728: // m_fontScaleMultiplier *= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1; m_baselineOffsetStack.Push(m_baselineOffset); m_baselineOffset += m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier; m_fontStyleStack.Add(FontStyles.Subscript); m_style |= FontStyles.Subscript; return true; case 22673: // case 20849: // if ((m_style & FontStyles.Subscript) == FontStyles.Subscript) { if (m_fontScaleMultiplier < 1) { //m_baselineOffset -= m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier; m_baselineOffset = m_baselineOffsetStack.Pop(); m_fontScaleMultiplier /= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1; } if (m_fontStyleStack.Remove(FontStyles.Subscript) == 0) m_style &= ~FontStyles.Subscript; } return true; case 6566: // case 4742: // m_fontScaleMultiplier *= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1; m_baselineOffsetStack.Push(m_baselineOffset); m_baselineOffset += m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier; m_fontStyleStack.Add(FontStyles.Superscript); m_style |= FontStyles.Superscript; return true; case 22687: // case 20863: // if ((m_style & FontStyles.Superscript) == FontStyles.Superscript) { if (m_fontScaleMultiplier < 1) { //m_baselineOffset -= m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier; m_baselineOffset = m_baselineOffsetStack.Pop(); m_fontScaleMultiplier /= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1; } if (m_fontStyleStack.Remove(FontStyles.Superscript) == 0) m_style &= ~FontStyles.Superscript; } return true; case -330774850: // case 2012149182: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; if ((m_fontStyle & FontStyles.Bold) == FontStyles.Bold) { // Nothing happens since Bold is forced on the text. //m_fontWeight = 700; return true; } // Remove bold style m_style &= ~FontStyles.Bold; switch ((int)value) { case 100: m_fontWeightInternal = 100; break; case 200: m_fontWeightInternal = 200; break; case 300: m_fontWeightInternal = 300; break; case 400: m_fontWeightInternal = 400; break; case 500: m_fontWeightInternal = 500; break; case 600: m_fontWeightInternal = 600; break; case 700: m_fontWeightInternal = 700; m_style |= FontStyles.Bold; break; case 800: m_fontWeightInternal = 800; break; case 900: m_fontWeightInternal = 900; break; } m_fontWeightStack.Add(m_fontWeightInternal); return true; case -1885698441: // case 457225591: // m_fontWeightInternal = m_fontWeightStack.Remove(); if (m_fontWeightInternal == 400) m_style &= ~FontStyles.Bold; return true; case 6380: // case 4556: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: //if (m_xmlAttribute[1].nameHashCode == 275917) // //{ // // left = 3774683 // // right= 136703040 // if (m_xmlAttribute [1].valueHashCode == 136703040) // { // // track the endindex so we can return to this character. // Debug.Log ("align=right startIndex" + endIndex); // } //} m_xAdvance = value; //m_isIgnoringAlignment = true; return true; case TagUnits.FontUnits: m_xAdvance = value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; //m_isIgnoringAlignment = true; return true; case TagUnits.Percentage: m_xAdvance = m_marginWidth * value / 100; //if (m_xmlAttribute[1].nameHashCode == 275917) // //{ // //Debug.Log ("align tag."); // // left = 3774683 // // right= 136703040 // if (m_xmlAttribute [1].valueHashCode == 136703040) // { // // track the endindex so we can return to this character. // SaveWordWrappingState (ref m_SavedAlignment, endIndex, m_characterCount); // } //} //m_isIgnoringAlignment = true; return true; } return false; case 22501: // case 20677: // /* // Should retrun the index of where the tag started and adjust xAdvance. if (m_isParsingText) { if (m_SavedAlignment.previous_WordBreak != 0) { float current_xAdvance = m_xAdvance; endIndex = RestoreWordWrappingState (ref m_SavedAlignment); m_characterCount -= 1; m_xAdvance -= current_xAdvance - m_xAdvance; } m_SavedAlignment.previous_WordBreak = 0; m_isIgnoringAlignment = false; } */ m_isIgnoringAlignment = false; return true; case 16034505: // case 11642281: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: m_baselineOffset = value; return true; case TagUnits.FontUnits: m_baselineOffset = value * m_fontScale * m_fontAsset.fontInfo.Ascender; return true; case TagUnits.Percentage: //m_baselineOffset = m_marginHeight * val / 100; return false; } return false; case 54741026: // case 50348802: // m_baselineOffset = 0; return true; case 43991: // case 31191: // // This tag only works when Overflow - Page mode is used. if (m_overflowMode == TextOverflowModes.Page) { m_xAdvance = 0 + tag_LineIndent + tag_Indent; m_lineOffset = 0; m_pageNumber += 1; m_isNewPage = true; } return true; //
tag is now handled inline where it is replaced by a linefeed or \n. //case 544: //
//case 800: //
// m_forceLineBreak = true; // return true; case 43969: // case 31169: // m_isNonBreakingSpace = true; return true; case 156816: // case 144016: // m_isNonBreakingSpace = false; return true; case 45545: // case 32745: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: if (m_htmlTag[5] == 43) // { m_currentFontSize = m_fontSize + value; m_sizeStack.Add(m_currentFontSize); m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; } else if (m_htmlTag[5] == 45) // { m_currentFontSize = m_fontSize + value; m_sizeStack.Add(m_currentFontSize); m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; } else // { m_currentFontSize = value; m_sizeStack.Add(m_currentFontSize); m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; } case TagUnits.FontUnits: m_currentFontSize = m_fontSize * value; m_sizeStack.Add(m_currentFontSize); m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; case TagUnits.Percentage: m_currentFontSize = m_fontSize * value / 100; m_sizeStack.Add(m_currentFontSize); m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; } return false; case 158392: // case 145592: // m_currentFontSize = m_sizeStack.Remove(); m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; case 41311: // case 28511: // //Debug.Log("Font name: \"" + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength) + "\" HashCode: " + m_xmlAttribute[0].valueHashCode + " Material Name: \"" + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength) + "\" Hashcode: " + m_xmlAttribute[1].valueHashCode); int fontHashCode = m_xmlAttribute[0].valueHashCode; int materialAttributeHashCode = m_xmlAttribute[1].nameHashCode; int materialHashCode = m_xmlAttribute[1].valueHashCode; // Special handling for or if (fontHashCode == 764638571 || fontHashCode == 523367755) { m_currentFontAsset = m_materialReferences[0].fontAsset; m_currentMaterial = m_materialReferences[0].material; m_currentMaterialIndex = 0; //Debug.Log(" assigning Font Asset [" + m_currentFontAsset.name + "] with Material [" + m_currentMaterial.name + "]."); m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); m_materialReferenceStack.Add(m_materialReferences[0]); return true; } TMP_FontAsset tempFont; Material tempMaterial; // HANDLE NEW FONT ASSET if (MaterialReferenceManager.TryGetFontAsset(fontHashCode, out tempFont)) { //if (tempFont != m_currentFontAsset) //{ // //Debug.Log("Assigning Font Asset: " + tempFont.name); // m_currentFontAsset = tempFont; // m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); //} } else { // Load Font Asset tempFont = Resources.Load(TMP_Settings.defaultFontAssetPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength)); if (tempFont == null) return false; // Add new reference to the font asset as well as default material to the MaterialReferenceManager MaterialReferenceManager.AddFontAsset(tempFont); } // HANDLE NEW MATERIAL if (materialAttributeHashCode == 0 && materialHashCode == 0) { // No material specified then use default font asset material. m_currentMaterial = tempFont.material; m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup); m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]); } else if (materialAttributeHashCode == 103415287 || materialAttributeHashCode == 72669687) // using material attribute { if (MaterialReferenceManager.TryGetMaterial(materialHashCode, out tempMaterial)) { m_currentMaterial = tempMaterial; m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup); m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]); } else { // Load new material tempMaterial = Resources.Load(TMP_Settings.defaultFontAssetPath + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength)); if (tempMaterial == null) return false; // Add new reference to this material in the MaterialReferenceManager MaterialReferenceManager.AddFontMaterial(materialHashCode, tempMaterial); m_currentMaterial = tempMaterial; m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup); m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]); } } else return false; m_currentFontAsset = tempFont; m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; case 154158: // case 141358: // { MaterialReference materialReference = m_materialReferenceStack.Remove(); m_currentFontAsset = materialReference.fontAsset; m_currentMaterial = materialReference.material; m_currentMaterialIndex = materialReference.index; m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f)); return true; } case 103415287: // case 72669687: // materialHashCode = m_xmlAttribute[0].valueHashCode; // Special handling for or if (materialHashCode == 764638571 || materialHashCode == 523367755) { // Check if material font atlas texture matches that of the current font asset. //if (m_currentFontAsset.atlas.GetInstanceID() != m_currentMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) return false; m_currentMaterial = m_materialReferences[0].material; m_currentMaterialIndex = 0; m_materialReferenceStack.Add(m_materialReferences[0]); return true; } // Check if material if (MaterialReferenceManager.TryGetMaterial(materialHashCode, out tempMaterial)) { // Check if material font atlas texture matches that of the current font asset. //if (m_currentFontAsset.atlas.GetInstanceID() != tempMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) return false; m_currentMaterial = tempMaterial; m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup); m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]); } else { // Load new material tempMaterial = Resources.Load(TMP_Settings.defaultFontAssetPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength)); if (tempMaterial == null) return false; // Check if material font atlas texture matches that of the current font asset. //if (m_currentFontAsset.atlas.GetInstanceID() != tempMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) return false; // Add new reference to this material in the MaterialReferenceManager MaterialReferenceManager.AddFontMaterial(materialHashCode, tempMaterial); m_currentMaterial = tempMaterial; m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset , m_materialReferences, m_materialReferenceIndexLookup); m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]); } return true; case 374360934: // case 343615334: // { //if (m_currentMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_materialReferenceStack.PreviousItem().material.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) // return false; MaterialReference materialReference = m_materialReferenceStack.Remove(); m_currentMaterial = materialReference.material; m_currentMaterialIndex = materialReference.index; return true; } case 320078: // case 230446: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: m_xAdvance += value; return true; case TagUnits.FontUnits: m_xAdvance += value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; return true; case TagUnits.Percentage: // Not applicable return false; } return false; case 276254: // case 186622: // if (m_xmlAttribute[0].valueLength != 3) return false; m_htmlColor.a = (byte)(HexToInt(m_htmlTag[7]) * 16 + HexToInt(m_htmlTag[8])); return true; case 1750458: // return false; case 426: // return true; case 43066: // case 30266: // if (m_isParsingText && !m_isCalculatingPreferredValues) { int index = m_textInfo.linkCount; if (index + 1 > m_textInfo.linkInfo.Length) TMP_TextInfo.Resize(ref m_textInfo.linkInfo, index + 1); m_textInfo.linkInfo[index].textComponent = this; m_textInfo.linkInfo[index].hashCode = m_xmlAttribute[0].valueHashCode; m_textInfo.linkInfo[index].linkTextfirstCharacterIndex = m_characterCount; m_textInfo.linkInfo[index].linkIdFirstCharacterIndex = startIndex + m_xmlAttribute[0].valueStartIndex; m_textInfo.linkInfo[index].linkIdLength = m_xmlAttribute[0].valueLength; m_textInfo.linkInfo[index].SetLinkID(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); } return true; case 155913: // case 143113: // if (m_isParsingText && !m_isCalculatingPreferredValues) { if (m_textInfo.linkCount < m_textInfo.linkInfo.Length) { m_textInfo.linkInfo[m_textInfo.linkCount].linkTextLength = m_characterCount - m_textInfo.linkInfo[m_textInfo.linkCount].linkTextfirstCharacterIndex; m_textInfo.linkCount += 1; } } return true; case 275917: // case 186285: // switch (m_xmlAttribute[0].valueHashCode) { case 3774683: // m_lineJustification = TextAlignmentOptions.Left; m_lineJustificationStack.Add(m_lineJustification); return true; case 136703040: // m_lineJustification = TextAlignmentOptions.Right; m_lineJustificationStack.Add(m_lineJustification); return true; case -458210101: // m_lineJustification = TextAlignmentOptions.Center; m_lineJustificationStack.Add(m_lineJustification); return true; case -523808257: // m_lineJustification = TextAlignmentOptions.Justified; m_lineJustificationStack.Add(m_lineJustification); return true; case 122383428: // m_lineJustification = TextAlignmentOptions.Flush; m_lineJustificationStack.Add(m_lineJustification); return true; } return false; case 1065846: // case 976214: // m_lineJustification = m_lineJustificationStack.Remove(); return true; case 327550: // case 237918: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: m_width = value; break; case TagUnits.FontUnits: return false; //break; case TagUnits.Percentage: m_width = m_marginWidth * value / 100; break; } return true; case 1117479: // case 1027847: // m_width = -1; return true; // STYLE tag is now handled inline and replaced by its definition. //case 322689: // //case 233057: // //case 1022986: // // style = TMP_StyleSheet.GetStyle(m_xmlAttribute[0].valueHashCode); // if (style == null) // { // // Get style from the Style Stack // int styleHashCode = m_styleStack.CurrentItem(); // style = TMP_StyleSheet.GetStyle(styleHashCode); // m_styleStack.Remove(); // } // if (style == null) return false; // //// Parse Style Macro // for (int i = 0; i < style.styleClosingTagArray.Length; i++) // { // if (style.styleClosingTagArray[i] == 60) // ValidateHtmlTag(style.styleClosingTagArray, i + 1, out i); // } // return true; case 281955: // or case 192323: // // 3 Hex (short hand) if (m_htmlTag[6] == 35 && tagCharCount == 10) { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } // 4 Hex (short hand) else if (m_htmlTag[6] == 35 && tagCharCount == 11) { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } // 3 Hex pairs if (m_htmlTag[6] == 35 && tagCharCount == 13) { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } // 4 Hex pairs else if (m_htmlTag[6] == 35 && tagCharCount == 15) { m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount); m_colorStack.Add(m_htmlColor); return true; } // switch (m_xmlAttribute[0].valueHashCode) { case 125395: // m_htmlColor = Color.red; m_colorStack.Add(m_htmlColor); return true; case 3573310: // m_htmlColor = Color.blue; m_colorStack.Add(m_htmlColor); return true; case 117905991: // m_htmlColor = Color.black; m_colorStack.Add(m_htmlColor); return true; case 121463835: // m_htmlColor = Color.green; m_colorStack.Add(m_htmlColor); return true; case 140357351: // m_htmlColor = Color.white; m_colorStack.Add(m_htmlColor); return true; case 26556144: // m_htmlColor = new Color32(255, 128, 0, 255); m_colorStack.Add(m_htmlColor); return true; case -36881330: // m_htmlColor = new Color32(160, 32, 240, 255); m_colorStack.Add(m_htmlColor); return true; case 554054276: // m_htmlColor = Color.yellow; m_colorStack.Add(m_htmlColor); return true; } return false; case 100149144: // case 69403544: // int gradientPresetHashCode = m_xmlAttribute[0].valueHashCode; TMP_ColorGradient tempColorGradientPreset; // Check if Color Gradient Preset has already been loaded. if (MaterialReferenceManager.TryGetColorGradientPreset(gradientPresetHashCode, out tempColorGradientPreset)) { m_colorGradientPreset = tempColorGradientPreset; } else { // Load Color Gradient Preset if (tempColorGradientPreset == null) { tempColorGradientPreset = Resources.Load(TMP_Settings.defaultColorGradientPresetsPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength)); } if (tempColorGradientPreset == null) return false; MaterialReferenceManager.AddColorGradientPreset(gradientPresetHashCode, tempColorGradientPreset); m_colorGradientPreset = tempColorGradientPreset; } m_colorGradientStack.Add(m_colorGradientPreset); // TODO : Add support for defining preset in the tag itself return true; case 371094791: // case 340349191: // m_colorGradientPreset = m_colorGradientStack.Remove(); return true; case 1983971: // case 1356515: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: m_cSpacing = value; break; case TagUnits.FontUnits: m_cSpacing = value; m_cSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; break; case TagUnits.Percentage: return false; } return true; case 7513474: // case 6886018: //
if (!m_isParsingText) return true; // Adjust xAdvance to remove extra space from last character. if (m_characterCount > 0) { m_xAdvance -= m_cSpacing; m_textInfo.characterInfo[m_characterCount - 1].xAdvance = m_xAdvance; } m_cSpacing = 0; return true; case 2152041: // case 1524585: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: m_monoSpacing = value; break; case TagUnits.FontUnits: m_monoSpacing = value; m_monoSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; break; case TagUnits.Percentage: return false; } return true; case 7681544: // case 7054088: // m_monoSpacing = 0; return true; case 280416: // return false; case 1071884: // case 982252: // m_htmlColor = m_colorStack.Remove(); return true; case 2068980: // case 1441524: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: tag_Indent = value; break; case TagUnits.FontUnits: tag_Indent = value; tag_Indent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; break; case TagUnits.Percentage: tag_Indent = m_marginWidth * value / 100; break; } m_indentStack.Add(tag_Indent); m_xAdvance = tag_Indent; return true; case 7598483: // case 6971027: // tag_Indent = m_indentStack.Remove(); //m_xAdvance = tag_Indent; return true; case 1109386397: // case -842656867: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; switch (tagUnits) { case TagUnits.Pixels: tag_LineIndent = value; break; case TagUnits.FontUnits: tag_LineIndent = value; tag_LineIndent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; break; case TagUnits.Percentage: tag_LineIndent = m_marginWidth * value / 100; break; } m_xAdvance += tag_LineIndent; return true; case -445537194: // case 1897386838: // tag_LineIndent = 0; return true; case 2246877: // case 1619421: // int spriteAssetHashCode = m_xmlAttribute[0].valueHashCode; TMP_SpriteAsset tempSpriteAsset; m_spriteIndex = -1; // CHECK TAG FORMAT if (m_xmlAttribute[0].valueType == TagType.None || m_xmlAttribute[0].valueType == TagType.NumericalValue) { // No Sprite Asset is assigned to the text object if (m_spriteAsset != null) { m_currentSpriteAsset = m_spriteAsset; } else if (m_defaultSpriteAsset != null) { m_currentSpriteAsset = m_defaultSpriteAsset; } else if (m_defaultSpriteAsset == null) { if (TMP_Settings.defaultSpriteAsset != null) m_defaultSpriteAsset = TMP_Settings.defaultSpriteAsset; else m_defaultSpriteAsset = Resources.Load("Sprite Assets/Default Sprite Asset"); m_currentSpriteAsset = m_defaultSpriteAsset; } // No valid sprite asset available if (m_currentSpriteAsset == null) return false; } else { // A Sprite Asset has been specified if (MaterialReferenceManager.TryGetSpriteAsset(spriteAssetHashCode, out tempSpriteAsset)) { m_currentSpriteAsset = tempSpriteAsset; } else { // Load Sprite Asset if (tempSpriteAsset == null) { tempSpriteAsset = Resources.Load(TMP_Settings.defaultSpriteAssetPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength)); } if (tempSpriteAsset == null) return false; //Debug.Log("Loading & assigning new Sprite Asset: " + tempSpriteAsset.name); MaterialReferenceManager.AddSpriteAsset(spriteAssetHashCode, tempSpriteAsset); m_currentSpriteAsset = tempSpriteAsset; } } // Handling of legacy tag format. if (m_xmlAttribute[0].valueType == TagType.NumericalValue) // { int index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (index == -9999) return false; // Check to make sure sprite index is valid if (index > m_currentSpriteAsset.spriteInfoList.Count - 1) return false; m_spriteIndex = index; } m_spriteColor = s_colorWhite; m_tintSprite = false; // Handle Sprite Tag Attributes for (int i = 0; i < m_xmlAttribute.Length && m_xmlAttribute[i].nameHashCode != 0; i++) { //Debug.Log("Attribute[" + i + "].nameHashCode=" + m_xmlAttribute[i].nameHashCode + " Value:" + ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength)); int nameHashCode = m_xmlAttribute[i].nameHashCode; int index = 0; switch (nameHashCode) { case 43347: // case 30547: // m_currentSpriteAsset = TMP_SpriteAsset.SearchForSpriteByHashCode(m_currentSpriteAsset, m_xmlAttribute[i].valueHashCode, true, out index); if (index == -1) return false; m_spriteIndex = index; break; case 295562: // case 205930: // index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength); if (index == -9999) return false; // Check to make sure sprite index is valid if (index > m_currentSpriteAsset.spriteInfoList.Count - 1) return false; m_spriteIndex = index; break; case 45819: // tint case 33019: // TINT m_tintSprite = ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength) != 0; break; case 281955: // color=#FF00FF80 case 192323: // COLOR m_spriteColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength); break; case 39505: // anim="0,16,12" start, end, fps case 26705: // ANIM //Debug.Log("Start: " + m_xmlAttribute[i].valueStartIndex + " Length: " + m_xmlAttribute[i].valueLength); int paramCount = GetAttributeParameters(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength, ref m_attributeParameterValues); if (paramCount != 3) return false; m_spriteIndex = (int)m_attributeParameterValues[0]; if (m_isParsingText) { // TODO : fix this! //if (m_attributeParameterValues[0] > m_currentSpriteAsset.spriteInfoList.Count - 1 || m_attributeParameterValues[1] > m_currentSpriteAsset.spriteInfoList.Count - 1) // return false; spriteAnimator.DoSpriteAnimation(m_characterCount, m_currentSpriteAsset, m_spriteIndex, (int)m_attributeParameterValues[1], (int)m_attributeParameterValues[2]); } break; //case 45545: // size //case 32745: // SIZE // break; default: if (nameHashCode != 2246877 && nameHashCode != 1619421) return false; break; } } if (m_spriteIndex == -1) return false; // Material HashCode for the Sprite Asset is the Sprite Asset Hash Code m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentSpriteAsset.material, m_currentSpriteAsset, m_materialReferences, m_materialReferenceIndexLookup); m_textElementType = TMP_TextElementType.Sprite; return true; case 730022849: // case 514803617: // m_style |= FontStyles.LowerCase; m_fontStyleStack.Add(FontStyles.LowerCase); return true; case -1668324918: // case -1883544150: // if (m_fontStyleStack.Remove(FontStyles.LowerCase) == 0) m_style &= ~FontStyles.LowerCase; return true; case 13526026: // case 9133802: // case 781906058: // case 566686826: // m_style |= FontStyles.UpperCase; m_fontStyleStack.Add(FontStyles.UpperCase); return true; case 52232547: // case 47840323: // case -1616441709: // case -1831660941: // if (m_fontStyleStack.Remove(FontStyles.UpperCase) == 0) m_style &= ~FontStyles.UpperCase; return true; case 766244328: // case 551025096: // m_style |= FontStyles.SmallCaps; m_fontStyleStack.Add(FontStyles.SmallCaps); return true; case -1632103439: // case -1847322671: // if (m_fontStyleStack.Remove(FontStyles.SmallCaps) == 0) m_style &= ~FontStyles.SmallCaps; return true; case 2109854: // case 1482398: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); // px if (value == -9999) return false; m_marginLeft = value; switch (tagUnits) { case TagUnits.Pixels: // Default behavior break; case TagUnits.FontUnits: m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; break; case TagUnits.Percentage: m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100; break; } m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0; m_marginRight = m_marginLeft; return true; case 7639357: // case 7011901: // m_marginLeft = 0; m_marginRight = 0; return true; case 1100728678: // case -855002522: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); // px if (value == -9999) return false; m_marginLeft = value; switch (tagUnits) { case TagUnits.Pixels: // Default behavior break; case TagUnits.FontUnits: m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; break; case TagUnits.Percentage: m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100; break; } m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0; return true; case -884817987: // case -1690034531: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); // px if (value == -9999) return false; m_marginRight = value; switch (tagUnits) { case TagUnits.Pixels: // Default behavior break; case TagUnits.FontUnits: m_marginRight *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize; break; case TagUnits.Percentage: m_marginRight = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginRight / 100; break; } m_marginRight = m_marginRight >= 0 ? m_marginRight : 0; return true; case 1109349752: // case -842693512: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999 || value == 0) return false; m_lineHeight = value; switch (tagUnits) { case TagUnits.Pixels: //m_lineHeight = value; break; case TagUnits.FontUnits: m_lineHeight *= m_fontAsset.fontInfo.LineHeight * m_fontScale; break; case TagUnits.Percentage: m_lineHeight = m_fontAsset.fontInfo.LineHeight * m_lineHeight / 100 * m_fontScale; break; } return true; case -445573839: // case 1897350193: // m_lineHeight = TMP_Math.FLOAT_UNSET; return true; case 15115642: // case 10723418: // tag_NoParsing = true; return true; case 1913798: // case 1286342: // int actionID = m_xmlAttribute[0].valueHashCode; if (m_isParsingText) { m_actionStack.Add(actionID); Debug.Log("Action ID: [" + actionID + "] First character index: " + m_characterCount); } //if (m_isParsingText) //{ // TMP_Action action = TMP_Action.GetAction(m_xmlAttribute[0].valueHashCode); //} return true; case 7443301: // case 6815845: // if (m_isParsingText) { Debug.Log("Action ID: [" + m_actionStack.CurrentItem() + "] Last character index: " + (m_characterCount - 1)); } m_actionStack.Remove(); return true; case 315682: // case 226050: // value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; m_FXMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(value, 1, 1)); m_isFXMatrixSet = true; return true; case 1105611: // case 1015979: // m_isFXMatrixSet = false; return true; case 2227963: // case 1600507: // // TODO: Add ability to use Random Rotation value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); if (value == -9999) return false; m_FXMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, 0, value), Vector3.one); m_isFXMatrixSet = true; return true; case 7757466: // case 7130010: // m_isFXMatrixSet = false; return true; case 317446: // case 227814: //
switch (m_xmlAttribute[1].nameHashCode) { case 327550: // width float tableWidth = ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength); switch (tagUnits) { case TagUnits.Pixels: Debug.Log("Table width = " + tableWidth + "px."); break; case TagUnits.FontUnits: Debug.Log("Table width = " + tableWidth + "em."); break; case TagUnits.Percentage: Debug.Log("Table width = " + tableWidth + "%."); break; } break; } return true; case 1107375: //
case 1017743: // return true; case 926: // case 670: // return true; case 3229: // case 2973: // return true; case 916: // case 660: // // Set style to bold and center alignment return true; case 3219: // case 2963: // return true; case 912: // case 656: // // Style options for (int i = 1; i < m_xmlAttribute.Length && m_xmlAttribute[i].nameHashCode != 0; i++) { switch (m_xmlAttribute[i].nameHashCode) { case 327550: // width float tableWidth = ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength); switch (tagUnits) { case TagUnits.Pixels: Debug.Log("Table width = " + tableWidth + "px."); break; case TagUnits.FontUnits: Debug.Log("Table width = " + tableWidth + "em."); break; case TagUnits.Percentage: Debug.Log("Table width = " + tableWidth + "%."); break; } break; case 275917: // align switch (m_xmlAttribute[i].valueHashCode) { case 3774683: // left Debug.Log("TD align=\"left\"."); break; case 136703040: // right Debug.Log("TD align=\"right\"."); break; case -458210101: // center Debug.Log("TD align=\"center\"."); break; case -523808257: // justified Debug.Log("TD align=\"justified\"."); break; } break; } } return true; case 3215: // case 2959: // return true; } } return false; } } }