/// <summary> /// Function used to evaluate the length of a text string. /// </summary> /// <param name="text"></param> /// <returns></returns> public TextInfo GetTextInfo(string text) { TextInfo temp_textInfo = new TextInfo(); // Early exit if no font asset was assigned. This should not be needed since Arial SDF will be assigned by default. if (m_fontAsset.characterDictionary == null) { Debug.Log("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID()); return(null); } // Early exit if string is empty. if (text == null || text.Length == 0) { return(null); } // Convert String to Char[] StringToCharArray(text, ref m_text_buffer); int size = GetArraySizes(m_text_buffer); temp_textInfo.characterInfo = new TMPro_CharacterInfo[size]; m_fontIndex = 0; m_fontAssetArray[m_fontIndex] = m_fontAsset; // Scale the font to approximately match the point size m_fontScale = (m_fontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f)); float baseScale = m_fontScale; // BaseScale keeps the character aligned vertically since <size=+000> results in font of different scale. int charCode = 0; // Holds the character code of the currently being processed character. int prev_charCode = 0; //bool isMissingCharacter; // Used to handle missing characters in the Font Atlas / Definition. m_style = FontStyles.Normal; // Set defaul style as normal. // GetPadding to adjust the size of the mesh due to border thickness, softness, glow, etc... if (checkPaddingRequired) { checkPaddingRequired = false; m_padding = ShaderUtilities.GetPadding(m_renderer.sharedMaterials, m_enableExtraPadding, m_isUsingBold); m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial); } float style_padding = 0; // Extra padding required to accomodate Bold style. float xadvance_multiplier = 1; // Used to increase spacing between character when style is bold. m_baselineOffset = 0; // Used by subscript characters. float lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing). m_xAdvance = 0; // Used to track the position of each character. int lineNumber = 0; int wordCount = 0; int character_Count = 0; // Total characters in the char[] int visibleCharacter_Count = 0; // # of visible characters. // Limit Line Length to whatever size fits all characters on a single line. m_lineLength = m_lineLength > max_LineWrapLength ? max_LineWrapLength : m_lineLength; // Initialize struct to track states of word wrapping m_SaveWordWrapState = new WordWrapState(); int wrappingIndex = 0; if (temp_textInfo.lineInfo == null) { temp_textInfo.lineInfo = new LineInfo[8]; } for (int i = 0; i < temp_textInfo.lineInfo.Length; i++) { temp_textInfo.lineInfo[i] = new LineInfo(); //m_textInfo.lineInfo[i].lineExtents = new Extents(k_InfinityVector, -k_InfinityVector); } // Tracking of the highest Ascender float maxAscender = 0; float maxDescender = 0; int lastLineNumber = 0; int endTagIndex = 0; // Parse through Character buffer to read html tags and begin creating mesh. for (int i = 0; m_text_buffer[i] != 0; i++) { m_tabSpacing = -999; m_spacing = -999; charCode = m_text_buffer[i]; if (m_isRichText && charCode == 60) // '<' { // Check if Tag is valid. If valid, skip to the end of the validated tag. if (ValidateHtmlTag(m_text_buffer, i + 1, out endTagIndex)) { i = endTagIndex; if (m_tabSpacing != -999) { // Move character to a fix position. Position expresses in characters (approximation). m_xAdvance = m_tabSpacing * m_cached_Underline_GlyphInfo.width * m_fontScale; } if (m_spacing != -999) { m_xAdvance += m_spacing * m_fontScale * m_cached_Underline_GlyphInfo.width; } continue; } } //isMissingCharacter = false; // Look up Character Data from Dictionary and cache it. m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode, out m_cached_GlyphInfo); if (m_cached_GlyphInfo == null) { // Character wasn't found in the Dictionary. m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(88, out m_cached_GlyphInfo); if (m_cached_GlyphInfo != null) { Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table."); // Replace the missing character by X (if it is found) charCode = 88; //isMissingCharacter = true; } else { // At this point the character isn't in the Dictionary, the replacement X isn't either so ... //continue; } } // Store some of the text object's information temp_textInfo.characterInfo[character_Count].character = (char)charCode; //temp_textInfo.characterInfo[character_Count].color = m_htmlColor; //temp_textInfo.characterInfo[character_Count].style = m_style; temp_textInfo.characterInfo[character_Count].index = (short)i; // Handle Kerning if Enabled. if (m_enableKerning && character_Count >= 1) { KerningPairKey keyValue = new KerningPairKey(prev_charCode, charCode); KerningPair pair; m_fontAsset.kerningDictionary.TryGetValue(keyValue.key, out pair); if (pair != null) { m_xAdvance += pair.XadvanceOffset * m_fontScale; } } // Set Padding based on selected font style if ((m_style & FontStyles.Bold) == FontStyles.Bold) // Checks for any combination of Bold Style. { style_padding = m_fontAsset.BoldStyle * 2; xadvance_multiplier = 1.07f; // Increase xAdvance for bold characters. } else { style_padding = m_fontAsset.NormalStyle * 2; xadvance_multiplier = 1.0f; } // Setup Vertices for each character. Vector3 top_left = new Vector3(0 + m_xAdvance + ((m_cached_GlyphInfo.xOffset - m_padding - style_padding) * m_fontScale), (m_cached_GlyphInfo.yOffset + m_baselineOffset + m_padding) * m_fontScale - lineOffset * baseScale, 0); Vector3 bottom_left = new Vector3(top_left.x, top_left.y - ((m_cached_GlyphInfo.height + m_padding * 2) * m_fontScale), 0); Vector3 top_right = new Vector3(bottom_left.x + ((m_cached_GlyphInfo.width + m_padding * 2 + style_padding * 2) * m_fontScale), top_left.y, 0); Vector3 bottom_right = new Vector3(top_right.x, bottom_left.y, 0); // Check if we need to Shear the rectangles for Italic styles if ((m_style & FontStyles.Italic) == FontStyles.Italic) { // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount. float shear_value = m_fontAsset.ItalicStyle * 0.01f; Vector3 topShear = new Vector3(shear_value * ((m_cached_GlyphInfo.yOffset + m_padding + style_padding) * m_fontScale), 0, 0); Vector3 bottomShear = new Vector3(shear_value * (((m_cached_GlyphInfo.yOffset - m_cached_GlyphInfo.height - m_padding - style_padding)) * m_fontScale), 0, 0); top_left = top_left + topShear; bottom_left = bottom_left + bottomShear; top_right = top_right + topShear; bottom_right = bottom_right + bottomShear; } // Track Word Count per line and for the object if (character_Count > 0 && (char.IsWhiteSpace((char)charCode) || char.IsPunctuation((char)charCode))) { if (char.IsLetterOrDigit(temp_textInfo.characterInfo[character_Count - 1].character)) { wordCount += 1; temp_textInfo.lineInfo[lineNumber].wordCount += 1; } } // Setup Mesh for visible characters. ie. not a SPACE / LINEFEED / CARRIAGE RETURN. if (charCode != 32 && charCode != 9 && charCode != 10 && charCode != 13) { // Determine the bounds of the Mesh. //meshExtents.min = new Vector2(Mathf.Min(meshExtents.min.x, bottom_left.x), Mathf.Min(meshExtents.min.y, bottom_left.y)); //meshExtents.max = new Vector2(Mathf.Max(meshExtents.max.x, top_right.x), Mathf.Max(meshExtents.max.y, top_left.y)); // Determine the extend of each line LineInfo lineInfo = temp_textInfo.lineInfo[lineNumber]; Extents lineExtents = lineInfo.lineExtents; temp_textInfo.lineInfo[lineNumber].lineExtents.min = new Vector2(Mathf.Min(lineExtents.min.x, bottom_left.x), Mathf.Min(lineExtents.min.y, bottom_left.y)); temp_textInfo.lineInfo[lineNumber].lineExtents.max = new Vector2(Mathf.Max(lineExtents.max.x, top_right.x), Mathf.Max(lineExtents.max.y, top_left.y)); if (m_enableWordWrapping && top_right.x > m_lineLength) { // Check if further wrapping is possible or if we need to increase the line length if (wrappingIndex == m_SaveWordWrapState.previous_WordBreak) { if (isAffectingWordWrapping) { m_lineLength = Mathf.Round(top_right.x * 100 + 0.5f) / 100f;//m_lineLength = top_right.x; GenerateTextMesh(); isAffectingWordWrapping = false; } Debug.Log("Line " + lineNumber + " Cannot wrap lines anymore."); return(null); } // Restore to previously stored state character_Count = m_SaveWordWrapState.total_CharacterCount + 1; visibleCharacter_Count = m_SaveWordWrapState.visible_CharacterCount; m_textInfo.lineInfo[lineNumber] = m_SaveWordWrapState.lineInfo; m_htmlColor = m_SaveWordWrapState.vertexColor; m_style = m_SaveWordWrapState.fontStyle; m_baselineOffset = m_SaveWordWrapState.baselineOffset; m_fontScale = m_SaveWordWrapState.fontScale; i = m_SaveWordWrapState.previous_WordBreak; wrappingIndex = i; // Used to dectect when line length can no longer be reduced. lineNumber += 1; // Check to make sure Array is large enough to hold a new line. if (lineNumber >= temp_textInfo.lineInfo.Length) { Array.Resize(ref temp_textInfo.lineInfo, Mathf.NextPowerOfTwo(lineNumber)); } lineOffset += (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing); m_xAdvance = 0; continue; } //visibleCharacter_Count += 1; } else { // This is a Space, Tab, LineFeed or Carriage Return // Track # of spaces per line which is used for line justification. if (charCode == 9 || charCode == 32) { //m_lineExtents[lineNumber].spaceCount += 1; temp_textInfo.lineInfo[lineNumber].spaceCount += 1; temp_textInfo.spaceCount += 1; } // 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. m_SaveWordWrapState.previous_WordBreak = i; m_SaveWordWrapState.total_CharacterCount = character_Count; m_SaveWordWrapState.visible_CharacterCount = visibleCharacter_Count; m_SaveWordWrapState.maxLineLength = m_xAdvance; m_SaveWordWrapState.fontScale = m_fontScale; m_SaveWordWrapState.baselineOffset = m_baselineOffset; m_SaveWordWrapState.fontStyle = m_style; m_SaveWordWrapState.vertexColor = m_htmlColor; m_SaveWordWrapState.lineInfo = temp_textInfo.lineInfo[lineNumber]; } // Store Rectangle positions for each Character. temp_textInfo.characterInfo[character_Count].bottomLeft = bottom_left; temp_textInfo.characterInfo[character_Count].topRight = top_right; temp_textInfo.characterInfo[character_Count].lineNumber = (short)lineNumber; //temp_textInfo.characterInfo[character_Count].baseLine = top_right.y - (m_cached_GlyphInfo.yOffset + m_padding) * m_fontScale; //temp_textInfo.characterInfo[character_Count].topLine = temp_textInfo.characterInfo[character_Count].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Ascender + m_alignmentPadding.y) * m_fontScale; // Ascender //temp_textInfo.characterInfo[character_Count].bottomLine = temp_textInfo.characterInfo[character_Count].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Descender - m_alignmentPadding.w) * m_fontScale; // Descender maxAscender = temp_textInfo.characterInfo[character_Count].topLine > maxAscender ? temp_textInfo.characterInfo[character_Count].topLine : maxAscender; maxDescender = temp_textInfo.characterInfo[character_Count].bottomLine < maxDescender ? temp_textInfo.characterInfo[character_Count].bottomLine : maxDescender; //temp_textInfo.characterInfo[character_Count].aspectRatio = m_cached_GlyphInfo.width / m_cached_GlyphInfo.height; //temp_textInfo.characterInfo[character_Count].scale = m_fontScale; temp_textInfo.lineInfo[lineNumber].characterCount += 1; //Debug.Log("Character #" + i + " is [" + (char)charCode + "] ASCII (" + charCode + ")"); // Store LineInfo if (lineNumber != lastLineNumber) { temp_textInfo.lineInfo[lineNumber].firstCharacterIndex = character_Count; temp_textInfo.lineInfo[lineNumber - 1].lastCharacterIndex = character_Count - 1; temp_textInfo.lineInfo[lineNumber - 1].characterCount = temp_textInfo.lineInfo[lineNumber - 1].lastCharacterIndex - temp_textInfo.lineInfo[lineNumber - 1].firstCharacterIndex + 1; temp_textInfo.lineInfo[lineNumber - 1].lineLength = temp_textInfo.characterInfo[character_Count - 1].topRight.x - m_padding * m_fontScale; } lastLineNumber = lineNumber; // Handle Tabulation Stops. Tab stops at every 25% of Font Size. if (charCode == 9) { m_xAdvance = (int)(m_xAdvance / (m_fontSize * 0.25f) + 1) * (m_fontSize * 0.25f); } else { m_xAdvance += (m_cached_GlyphInfo.xAdvance * xadvance_multiplier * m_fontScale) + m_characterSpacing; } // Handle Line Feed as well as Word Wrapping if (charCode == 10 || charCode == 13) { lineNumber += 1; // Check to make sure Array is large enough to hold a new line. if (lineNumber >= temp_textInfo.lineInfo.Length) { Array.Resize(ref temp_textInfo.lineInfo, Mathf.NextPowerOfTwo(lineNumber)); } lineOffset += (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing); m_xAdvance = 0; } character_Count += 1; prev_charCode = charCode; } temp_textInfo.lineInfo[lineNumber].lastCharacterIndex = character_Count - 1; temp_textInfo.lineInfo[lineNumber].characterCount = temp_textInfo.lineInfo[lineNumber].lastCharacterIndex - temp_textInfo.lineInfo[lineNumber].firstCharacterIndex + 1; temp_textInfo.lineInfo[lineNumber].lineLength = temp_textInfo.characterInfo[character_Count - 1].topRight.x - m_padding * m_fontScale; //m_textMetrics = new TMPro_TextMetrics(); temp_textInfo.characterCount = character_Count; temp_textInfo.lineCount = lineNumber + 1; temp_textInfo.wordCount = wordCount; //for (int i = 0; i < lineNumber + 1; i++) //{ // Debug.Log("Line: " + (i + 1) + " # Char: " + temp_textInfo.lineInfo[i].characterCount // + " Word Count: " + temp_textInfo.lineInfo[i].wordCount // + " Space: " + temp_textInfo.lineInfo[i].spaceCount // + " First:" + temp_textInfo.lineInfo[i].firstCharacterIndex + " Last [" + temp_textInfo.characterInfo[temp_textInfo.lineInfo[i].lastCharacterIndex].character // + "] at Index: " + temp_textInfo.lineInfo[i].lastCharacterIndex + " Length: " + temp_textInfo.lineInfo[i].lineLength // + " Line Extents: " + temp_textInfo.lineInfo[i].lineExtents); // //Debug.Log("line: " + (i + 1) + " m_lineExtents Count: " + m_lineExtents[i].characterCount + " lineInfo: " + m_textInfo.lineInfo[i].characterCount); // //Debug.DrawLine(new Vector3(m_textInfo.lineInfo[i].lineLength, 2, 0), new Vector3(m_textInfo.lineInfo[i].lineLength, -2, 0), Color.red, 30f); //} return(temp_textInfo); }
//public override Material defaultMaterial //{ // get { Debug.Log("Default Material called."); return m_sharedMaterial; } //} //public bool MaskEnabled() //{ // Debug.Log("MaskEnabled() called."); // return true; //} public void ParentMaskStateChanged() { //Debug.Log("***** PARENT MASK STATE CHANGED *****"); if (m_fontAsset == null) { return; } m_stencilID = MaterialManager.GetStencilID(gameObject); if (!m_isAwake) { return; } if (m_stencilID == 0) { if (m_maskingMaterial != null) { MaterialManager.ReleaseStencilMaterial(m_maskingMaterial); m_maskingMaterial = null; m_sharedMaterial = m_baseMaterial; } else if (m_fontMaterial != null) { m_sharedMaterial = MaterialManager.SetStencil(m_fontMaterial, 0); } } else { ShaderUtilities.GetShaderPropertyIDs(); if (m_fontMaterial != null) { m_sharedMaterial = MaterialManager.SetStencil(m_fontMaterial, m_stencilID); } else if (m_maskingMaterial == null) { m_maskingMaterial = MaterialManager.GetStencilMaterial(m_baseMaterial, m_stencilID); m_sharedMaterial = m_maskingMaterial; } else if (m_maskingMaterial.GetInt(ShaderUtilities.ID_StencilID) != m_stencilID || m_isNewBaseMaterial) { MaterialManager.ReleaseStencilMaterial(m_maskingMaterial); m_maskingMaterial = MaterialManager.GetStencilMaterial(m_baseMaterial, m_stencilID); m_sharedMaterial = m_maskingMaterial; } if (m_isMaskingEnabled) { EnableMasking(); } //Debug.Log("Masking Enabled. Assigning " + m_maskingMaterial.name + " with ID " + m_maskingMaterial.GetInstanceID()); } m_uiRenderer.SetMaterial(m_sharedMaterial, null); m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold); m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial); }