static int GetTextInfo(IntPtr L) { try { ToLua.CheckArgsCount(L, 2); TMPro.TextMeshProUGUI obj = (TMPro.TextMeshProUGUI)ToLua.CheckObject(L, 1, typeof(TMPro.TextMeshProUGUI)); string arg0 = ToLua.CheckString(L, 2); TMPro.TMP_TextInfo o = obj.GetTextInfo(arg0); ToLua.PushObject(L, o); return(1); } catch (Exception e) { return(LuaDLL.toluaL_exception(L, e)); } }
public IEnumerator BloopTextRoutine(string text) { textMesh.text = ""; yield return(null); float currentIndex = 0; int intIndex = 0; textMesh.maxVisibleCharacters = 0; textMesh.text = text; TMPro.TMP_TextInfo textInfo = textMesh.textInfo; yield return(null); int totalVisibleCharacters = textInfo.characterCount; // Get # of Visible Character in text object var characters = text.ToCharArray(); yield return(null); talker.StartAnimation(); targetPitch = UnityEngine.Random.Range(pitchRange.x, pitchRange.y); textMesh.enabled = true; while (currentIndex < totalVisibleCharacters) { currentIndex = Mathf.Min(currentIndex + (charsPerSecond * Time.deltaTime), totalVisibleCharacters); var i = Mathf.FloorToInt(currentIndex); if (i > intIndex && i > 0) { intIndex = i; char currentChar = characters[i - 1]; if (!char.IsWhiteSpace(currentChar)) { PlayBlip(i == characters.Length); } } textMesh.maxVisibleCharacters = intIndex; yield return(null); } talker.StopAfterFrame(); }
//private int loopCountB = 0; //private int loopCountC = 0; //private int loopCountD = 0; //private int loopCountE = 0; protected override void Awake() { //base.Awake(); //Debug.Log("***** Awake() *****"); m_isAwake = true; // Cache Reference to the Canvas m_canvas = GetComponentInParent(typeof(Canvas)) as Canvas; // Cache Reference to RectTransform. m_rectTransform = gameObject.GetComponent<RectTransform>(); if (m_rectTransform == null) m_rectTransform = gameObject.AddComponent<RectTransform>(); // Cache a reference to the UIRenderer. m_uiRenderer = GetComponent<CanvasRenderer>(); if (m_uiRenderer == null) m_uiRenderer = gameObject.AddComponent<CanvasRenderer> (); if (m_mesh == null) { //Debug.Log("Creating new mesh."); m_mesh = new Mesh(); m_mesh.hideFlags = HideFlags.HideAndDontSave; //m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0)); } // Cache reference to Mask Component if one is present //m_stencilID = MaterialManager.GetStencilID(gameObject); //m_mask = GetComponentInParent<Mask>(); // Load TMP Settings if (m_settings == null) m_settings = TMP_Settings.LoadDefaultSettings(); if (m_settings != null) { //m_enableWordWrapping = m_settings.enableWordWrapping; //m_enableKerning = m_settings.enableKerning; //m_enableExtraPadding = m_settings.enableExtraPadding; } // Load the font asset and assign material to renderer. LoadFontAsset(); // Load Default TMP StyleSheet TMP_StyleSheet.LoadDefaultStyleSheet(); // Allocate our initial buffers. m_char_buffer = new int[m_max_characters]; m_cached_GlyphInfo = new GlyphInfo(); m_isFirstAllocation = true; m_textInfo = new TMP_TextInfo(); m_textInfo.meshInfo.mesh = m_mesh; // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen. if (m_fontAsset == null) { Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this); return; } // Set Defaults for Font Auto-sizing if (m_fontSizeMin == 0) m_fontSizeMin = m_fontSize / 2; if (m_fontSizeMax == 0) m_fontSizeMax = m_fontSize * 2; //// Set flags to ensure our text is parsed and text re-drawn. isInputParsingRequired = true; m_havePropertiesChanged = true; m_rectTransformDimensionsChanged = true; ForceMeshUpdate(); // Added to force OnWillRenderObject() to be called in case object is not visible so we get initial bounds for the mesh. }
//private int loopCountB; //private int loopCountC; //private int loopCountD; //private int loopCountE; protected override void Awake() { //Debug.Log("Awake() called on Object ID " + GetInstanceID()); // Code to handle Compatibility related to the switch from Color32 to Color if (m_fontColor == Color.white && m_fontColor32 != Color.white) { Debug.LogWarning("Converting Vertex Colors from Color32 to Color.", this); m_fontColor = m_fontColor32; } m_textContainer = GetComponent<TextContainer>(); //if (m_textContainer == null) // m_textContainer = gameObject.AddComponent<TextContainer>(); // Cache Reference to the Mesh Renderer. m_renderer = GetComponent<Renderer>(); if (m_renderer == null) m_renderer = gameObject.AddComponent<Renderer>(); // Disable CanvasRenderer and hide it if (this.canvasRenderer != null) { this.canvasRenderer.hideFlags = HideFlags.HideInInspector; } // Cache Reference to RectTransform m_rectTransform = this.rectTransform; // Cache Reference to the transform; m_transform = this.transform; // Cache a reference to the Mesh Filter. m_meshFilter = GetComponent<MeshFilter>(); if (m_meshFilter == null) m_meshFilter = gameObject.AddComponent<MeshFilter>(); // Cache a reference to our mesh. if (m_mesh == null) { //Debug.Log("Creating new mesh."); m_mesh = new Mesh(); m_mesh.hideFlags = HideFlags.HideAndDontSave; m_meshFilter.mesh = m_mesh; //m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0)); } m_meshFilter.hideFlags = HideFlags.HideInInspector; // Load TMP Settings for new text object instances. if (m_settings == null) m_settings = TMP_Settings.LoadDefaultSettings(); if (m_settings != null) { if (m_isNewTextObject) { m_enableWordWrapping = m_settings.enableWordWrapping; m_enableKerning = m_settings.enableKerning; m_enableExtraPadding = m_settings.enableExtraPadding; m_isNewTextObject = false; } m_warningsDisabled = m_settings.warningsDisabled; } // Load the font asset and assign material to renderer. LoadFontAsset(); // Allocate our initial buffers. m_char_buffer = new int[m_max_characters]; m_cached_TextElement = new TMP_Glyph(); //m_vertices = new Vector3[0]; // m_isFirstAllocation = true; m_textInfo = new TMP_TextInfo(this); // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen. if (m_fontAsset == null) { Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this); return; } // Set Defaults for Font Auto-sizing if (m_fontSizeMin == 0) m_fontSizeMin = m_fontSize / 2; if (m_fontSizeMax == 0) m_fontSizeMax = m_fontSize * 2; //// Set flags to cause ensure our text is parsed and text redrawn. m_isInputParsingRequired = true; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; //ForceMeshUpdate(); // Force an update of the text object to pre-populate the TextInfo and Preferred values. }
// Restore the State of various variables used in the mesh creation loop. int RestoreWordWrappingState(ref WordWrapState state) { m_textInfo.lineInfo[m_lineNumber] = state.lineInfo; m_textInfo = state.textInfo != null ? state.textInfo : m_textInfo; m_currentFontSize = state.currentFontSize; m_fontScale = state.fontScale; m_baselineOffset = state.baselineOffset; m_style = state.fontStyle; //m_lineJustification = state.alignment; m_htmlColor = state.vertexColor; m_colorStackIndex = state.colorStackIndex; m_characterCount = state.total_CharacterCount + 1; m_visibleCharacterCount = state.visible_CharacterCount; m_visibleSpriteCount = state.visible_SpriteCount; m_firstVisibleCharacterOfLine = state.firstVisibleCharacterIndex; m_lastVisibleCharacterOfLine = state.lastVisibleCharIndex; m_meshExtents = state.meshExtents; m_xAdvance = state.xAdvance; m_maxAscender = state.maxAscender; m_maxDescender = state.maxDescender; m_preferredWidth = state.preferredWidth; m_preferredHeight = state.preferredHeight; m_lineNumber = state.lineNumber; m_lineOffset = state.lineOffset; //m_previousFontScale = state.previousLineScale; m_maxFontScale = state.maxFontScale; int index = state.previous_WordBreak; return index; }
//private int loopCountB = 0; //private int loopCountC = 0; //private int loopCountD = 0; //private int loopCountE = 0; protected override void Awake() { //base.Awake(); //Debug.Log("***** Awake() *****"); // on Object ID:" + GetInstanceID()); m_isAwake = true; // Cache Reference to the Canvas m_canvas = GetComponentInParent(typeof(Canvas)) as Canvas; // Cache Reference to RectTransform. m_rectTransform = gameObject.GetComponent<RectTransform>(); if (m_rectTransform == null) m_rectTransform = gameObject.AddComponent<RectTransform>(); // Cache a reference to the UIRenderer. m_uiRenderer = GetComponent<CanvasRenderer>(); if (m_uiRenderer == null) m_uiRenderer = gameObject.AddComponent<CanvasRenderer> (); //m_uiRenderer.hideFlags = HideFlags.HideInInspector; // Determine if the RectTransform is Driven m_layoutController = GetComponent(typeof(ILayoutController)) as ILayoutController ?? (transform.parent != null ? transform.parent.GetComponent(typeof(ILayoutController)) as ILayoutController : null); if (m_layoutController != null) IsRectTransformDriven = true; // Cache reference to Mask Component if one is present //m_stencilID = MaterialManager.GetStencilID(gameObject); //m_mask = GetComponentInParent<Mask>(); // Load the font asset and assign material to renderer. LoadFontAsset(); // Allocate our initial buffers. m_char_buffer = new int[m_max_characters]; m_cached_GlyphInfo = new GlyphInfo(); m_uiVertices = new UIVertex[0]; // m_isFirstAllocation = true; m_textInfo = new TMP_TextInfo(); //m_textInfo.wordInfo = new List<TMP_WordInfo>(); //m_textInfo.lineInfo = new TMP_LineInfo[m_max_numberOfLines]; //m_textInfo.pageInfo = new TMP_PageInfo[16]; //m_textInfo.meshInfo = new TMP_MeshInfo(); //m_textInfo.meshInfo.meshArrays = new UIVertex[17][]; // TODO : Add support for inline sprites and other fonts. m_fontAssetArray = new TextMeshProFont[16]; // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen. if (m_fontAsset == null) { Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject."); return; } // Set Defaults for Font Auto-sizing if (m_fontSizeMin == 0) m_fontSizeMin = m_fontSize / 2; if (m_fontSizeMax == 0) m_fontSizeMax = m_fontSize * 2; //// Set flags to ensure our text is parsed and text re-drawn. isInputParsingRequired = true; havePropertiesChanged = true; m_rectTransformDimensionsChanged = true; //m_isCalculateSizeRequired = true; ForceMeshUpdate(); // Added to force OnWillRenderObject() to be called in case object is not visible so we get initial bounds for the mesh. }
// This function parses through the Char[] to determine how many characters will be visible. It then makes sure the arrays are large enough for all those characters. protected override int SetArraySizes(int[] chars) { //Debug.Log("Set Array Size called."); int visibleCount = 0; int totalCount = 0; int tagEnd = 0; int spriteCount = 0; m_isUsingBold = false; m_isParsingText = false; m_textElementType = TMP_TextElementType.Character; m_VisibleCharacters.Clear(); m_currentFontAsset = m_fontAsset; 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; if (m_textElementType == TMP_TextElementType.Sprite) { spriteCount += 1; totalCount += 1; m_VisibleCharacters.Add((char)(57344 + m_spriteIndex)); m_textElementType = TMP_TextElementType.Character; } continue; } } if (!char.IsWhiteSpace((char)c)) { visibleCount += 1; } m_VisibleCharacters.Add((char)c); totalCount += 1; } // Allocated secondary vertex buffers for InlineGraphic Component if present. if (spriteCount > 0) { if (m_inlineGraphics == null) m_inlineGraphics = GetComponent<InlineGraphicManager>() ?? gameObject.AddComponent<InlineGraphicManager>(); m_inlineGraphics.AllocatedVertexBuffers(spriteCount); } else if (m_inlineGraphics != null) m_inlineGraphics.ClearUIVertex(); m_spriteCount = spriteCount; if (m_textInfo == null || m_textInfo.characterInfo == null || totalCount > m_textInfo.characterInfo.Length) { if (m_textInfo == null) m_textInfo = new TMP_TextInfo(); m_textInfo.characterInfo = new TMP_CharacterInfo[totalCount > 1024 ? totalCount + 256 : Mathf.NextPowerOfTwo(totalCount)]; } // Make sure our Mesh Buffer Allocations can hold these new Quads. if (m_textInfo.meshInfo[0].vertices == null) m_textInfo.meshInfo[0] = new TMP_MeshInfo(m_mesh, visibleCount); if (visibleCount * 4 > m_textInfo.meshInfo[0].vertices.Length) { // If this is the first allocation, we allocated exactly the number of Quads we need. Otherwise, we allocated more since this text object is dynamic. if (m_isFirstAllocation) { SetMeshArrays(visibleCount); m_isFirstAllocation = false; } else { SetMeshArrays(visibleCount > 1024 ? visibleCount + 256 : Mathf.NextPowerOfTwo(visibleCount)); } } return totalCount; }
//private int loopCountB = 0; //private int loopCountC = 0; //private int loopCountD = 0; //private int loopCountE = 0; protected override void Awake() { //base.Awake(); //Debug.Log("***** Awake() *****"); m_isAwake = true; // Cache Reference to the Canvas m_canvas = this.canvas; m_isOrthographic = true; // Cache Reference to RectTransform. m_rectTransform = gameObject.GetComponent<RectTransform>(); if (m_rectTransform == null) m_rectTransform = gameObject.AddComponent<RectTransform>(); // Cache a reference to the UIRenderer. m_uiRenderer = GetComponent<CanvasRenderer>(); if (m_uiRenderer == null) m_uiRenderer = gameObject.AddComponent<CanvasRenderer> (); if (m_mesh == null) { //Debug.Log("Creating new mesh."); m_mesh = new Mesh(); m_mesh.hideFlags = HideFlags.HideAndDontSave; //m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0)); } // Cache reference to Mask Component if one is present //m_stencilID = MaterialManager.GetStencilID(gameObject); //m_mask = GetComponentInParent<Mask>(); // Load TMP Settings for new text object instances. if (m_settings == null) m_settings = TMP_Settings.LoadDefaultSettings(); if (m_settings != null) { if (m_isNewTextObject) { m_enableWordWrapping = m_settings.enableWordWrapping; m_enableKerning = m_settings.enableKerning; m_enableExtraPadding = m_settings.enableExtraPadding; m_isNewTextObject = false; } m_warningsDisabled = m_settings.warningsDisabled; } // Load the font asset and assign material to renderer. LoadFontAsset(); // Load Default TMP StyleSheet TMP_StyleSheet.LoadDefaultStyleSheet(); // Allocate our initial buffers. m_char_buffer = new int[m_max_characters]; m_cached_TextElement = new TMP_Glyph(); m_isFirstAllocation = true; m_textInfo = new TMP_TextInfo(this); // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen. if (m_fontAsset == null) { Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this); return; } // Set Defaults for Font Auto-sizing if (m_fontSizeMin == 0) m_fontSizeMin = m_fontSize / 2; if (m_fontSizeMax == 0) m_fontSizeMax = m_fontSize * 2; //// Set flags to ensure our text is parsed and text re-drawn. m_isInputParsingRequired = true; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; //ForceMeshUpdate(); // Force an update of the text object to pre-populate the TextInfo and Preferred values used by Unity's Layout System. }
//private int loopCountB; //private int loopCountC; //private int loopCountD; //private int loopCountE; void Awake() { //Debug.Log("Awake() called on Object ID " + GetInstanceID()); // Code to handle Compatibility related to the switch from Color32 to Color if (m_fontColor == Color.white && m_fontColor32 != Color.white) { Debug.LogWarning("Converting Vertex Colors from Color32 to Color.", this); m_fontColor = m_fontColor32; } m_textContainer = GetComponent<TextContainer>(); if (m_textContainer == null) m_textContainer = gameObject.AddComponent<TextContainer>(); // Cache Reference to the Mesh Renderer. m_renderer = GetComponent<Renderer>(); if (m_renderer == null) m_renderer = gameObject.AddComponent<Renderer>(); // Cache Reference to the transform; m_transform = gameObject.transform; // Cache a reference to the Mesh Filter. m_meshFilter = GetComponent<MeshFilter>(); if (m_meshFilter == null) m_meshFilter = gameObject.AddComponent<MeshFilter>(); // Cache a reference to our mesh. if (m_mesh == null) { //Debug.Log("Creating new mesh."); m_mesh = new Mesh(); m_mesh.hideFlags = HideFlags.HideAndDontSave; m_meshFilter.mesh = m_mesh; //m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0)); } m_meshFilter.hideFlags = HideFlags.HideInInspector; // Load the font asset and assign material to renderer. LoadFontAsset(); // Allocate our initial buffers. m_char_buffer = new int[m_max_characters]; //m_parsedCharacters = new char[m_max_characters]; //m_lineExtents = new Mesh_Extents[m_max_numberOfLines]; m_cached_GlyphInfo = new GlyphInfo(); m_vertices = new Vector3[0]; // m_isFirstAllocation = true; m_textInfo = new TMP_TextInfo(); //m_fontAssetArray = new TextMeshProFont[16]; // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen. if (m_fontAsset == null) { Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this); return; } // Set Defaults for Font Auto-sizing if (m_fontSizeMin == 0) m_fontSizeMin = m_fontSize / 2; if (m_fontSizeMax == 0) m_fontSizeMax = m_fontSize * 2; //// Set flags to cause ensure our text is parsed and text redrawn. isInputParsingRequired = true; m_havePropertiesChanged = true; ForceMeshUpdate(); // Added to force OnWillRenderObject() to be called in case object is not visible so we get initial bounds for the mesh. }
public static void TextLayout <T>(T textElement, string contentText, RectTransform rectTrans, float viewWidth, ref float originX, ref float originY, ref float restWidth, ref float currentLineMaxHeight, ref List <RectTransform> lineContents, ref Vector2 wrappedSize) where T : LTElement, ILayoutableText { // 文字列が空な場合、何もせずに返す。 if (string.IsNullOrEmpty(contentText)) { return; } Debug.Assert(rectTrans.pivot.x == 0 && rectTrans.pivot.y == 1 && rectTrans.anchorMin.x == 0 && rectTrans.anchorMin.y == 1 && rectTrans.anchorMax.x == 0 && rectTrans.anchorMax.y == 1, "rectTransform for BasicLayoutFunctions.TextLayout should set pivot to 0,1 and anchorMin 0,1 anchorMax 0,1."); Debug.Assert(textElement.transform.childCount == 0, "BasicLayoutFunctions.TextLayout not allows text element which has child."); var continueContent = false; NextLine: var textComponent = textElement.GetComponent <TextMeshProUGUI>(); TMPro.TMP_TextInfo textInfos = null; { // wordWrappingを可能にすると、表示はともかく実際にこの行にどれだけの文字が入っているか判断できる。 textComponent.enableWordWrapping = true; textComponent.text = contentText; if (0 < textComponent.transform.childCount) { for (var i = 0; i < textComponent.transform.childCount; i++) { var childRectTrans = textComponent.transform.GetChild(i).GetComponent <RectTransform>(); childRectTrans.pivot = new Vector2(0, 1); childRectTrans.anchorMin = new Vector2(0, 1); childRectTrans.anchorMax = new Vector2(0, 1); childRectTrans.anchoredPosition = Vector2.zero; } } // 文字が入る箱のサイズを縦に無限にして、どの程度入るかのレイアウト情報を取得する。 textComponent.rectTransform.sizeDelta = new Vector2(restWidth, Screen.height); textInfos = textComponent.GetTextInfo(contentText); // 文字を中央揃えではなく適正な位置にセットするためにラッピングを解除する。 textComponent.enableWordWrapping = false; } // TODO: 直す // 絵文字が含まれている場合、画像と文字に分けてレイアウトを行う。 if (IsContainsSurrogatePairOrSprite(contentText)) { textComponent.text = string.Empty; // TMProが子オブジェクトを作っている場合があり、それらがあれば消す必要がある。 // 同じフレーム内で同じ絵文字を作るようなことをする場合、作成されないケースがあるため、子供の有無を条件として絵文字の有無を判断することはできなかった。 for (var i = 0; i < textComponent.transform.childCount; i++) { GameObject.Destroy(textComponent.transform.GetChild(i).gameObject); } // 絵文字が含まれている。 // 今後のレイアウトに自分自身を巻き込まないように、レイアウトから自分自身を取り外す lineContents.RemoveAt(lineContents.Count - 1); textComponent.rectTransform.sizeDelta = new Vector2(restWidth, 0);// 高さが0で問題ない。 // この内部で全てのレイアウトを終わらせる。 LayoutContentWithEmoji(textElement, contentText, viewWidth, ref originX, ref originY, ref restWidth, ref currentLineMaxHeight, ref lineContents, ref wrappedSize); return; } var tmGeneratorLines = textInfos.lineInfo; var lineSpacing = textComponent.lineSpacing; var tmLineCount = textInfos.lineCount; var firstLine = tmGeneratorLines[0]; var currentFirstLineWidth = firstLine.length; var currentFirstLineHeight = firstLine.lineHeight; var isHeadOfLine = originX == 0; var isMultiLined = 1 < tmLineCount; /* * 予定している1行目の文字の幅が予定幅を超えている = オーバーフローしている場合、次のケースがある * ・文字列の1行目の末尾がたまたま幅予算を超えてレイアウトされた * * この場合、溢れたケースとして文字列の長さを調整してレイアウトを行う。 */ var isTextOverflow = (viewWidth < originX + currentFirstLineWidth); // TMProで末尾がwhitespaceで終わっている場合、正しい幅を出せていなく、そのくせ改行設定などは正しい。 // 幅がわかる文字を用意し、スペース文字 + 文字をつくり、コンテンツの幅から文字の幅を引けば、スペースの幅が出せる。 // それを1単位として、末尾にあるスペースの幅 x 個数をやれば、このコンテンツの正しい幅が出せる。 if (Char.IsWhiteSpace(contentText[firstLine.lastCharacterIndex])) { // 行末の、whitespaceかそれに該当する非表示な要素の個数 var numEndWhiteSpaceCount = firstLine.lastCharacterIndex - firstLine.lastVisibleCharacterIndex; // サンプリングする対象を今回の文字列の末尾から取得する。 // このため、幅が異なるwhitespace扱いのものが混じっていても、正しい長さを返せない。 var samplingWhiteSpace = contentText[firstLine.lastCharacterIndex]; // 一時退避する var sourceText = textComponent.text; // 0の文字の幅を取得するためにtextComponentにセット、現在のフォントでの0の幅を計測する。 textComponent.text = "0"; var widthOf0 = textComponent.preferredWidth; // whitespace + 0の文字の幅を取得するためにtextComponentにセット、現在のフォントでのws + 0の幅を計測する。 textComponent.text = samplingWhiteSpace + "0"; // 差 = whitespaceの幅を取得する。 var singleWidthOfWhiteSpace = textComponent.preferredWidth - widthOf0; // 退避したテキストを戻す textComponent.text = sourceText; // 現在のコンテンツのX起点 + whitespaceが含まれない幅 + whitespace幅 * 個数 を足し、この行の正しい幅を出す。 var totalWidthWithSpaces = originX + currentFirstLineWidth + (singleWidthOfWhiteSpace * numEndWhiteSpaceCount); // 画面の幅と比較し、小さい方をとる。 // これは、whitespaceを使ってレイアウトした場合、TMProがリクエスト幅を超えたぶんのwhitespaceの計算をサボって、whitespaceではない文字が来た時点でその文字を頭とする改行を行うため。 // 最大でも画面幅になるようにする。 var maxWidth = Mathf.Min(viewWidth, totalWidthWithSpaces); // 行送りが発生しているため、この行の値の幅の更新はもう起きない。そのため、ここでwrappedSize.xを更新する。 wrappedSize.x = Mathf.Max(wrappedSize.x, maxWidth); } var status = TextLayoutDefinitions.GetTextLayoutStatus(isHeadOfLine, isMultiLined, isTextOverflow); switch (status) { case TextLayoutStatus.NotHeadAndSingle: case TextLayoutStatus.HeadAndSingle: { // 全文を表示して終了 textComponent.text = contentText; if (0 < textComponent.transform.childCount) { for (var i = 0; i < textComponent.transform.childCount; i++) { var childRectTrans = textComponent.transform.GetChild(i).GetComponent <RectTransform>(); childRectTrans.pivot = new Vector2(0, 1); childRectTrans.anchorMin = new Vector2(0, 1); childRectTrans.anchorMax = new Vector2(0, 1); childRectTrans.anchoredPosition = Vector2.zero; } } if (continueContent) { continueContent = false; restWidth = viewWidth - currentFirstLineWidth; currentLineMaxHeight = currentFirstLineHeight; } else { textComponent.rectTransform.anchoredPosition = new Vector2(originX, originY); } textComponent.rectTransform.sizeDelta = new Vector2(currentFirstLineWidth, currentFirstLineHeight); ContinueLine(ref originX, originY, currentFirstLineWidth, currentFirstLineHeight, ref currentLineMaxHeight, ref wrappedSize); break; } case TextLayoutStatus.NotHeadAndMulti: { // textComponent.text = "<indent=" + originX + "pixels>" でindentを付けられるが、これの恩恵を素直に受けられるケースが少ない。 // この行をレイアウトした際、行頭の文字のレイアウトが変わるようであれば、利用できない。 // 最適化としてはケースが複雑なので後回しにする。 // これは、この行 + 追加のHead ~ 系の複数のコンテンツに分割する。 var nextLineTextIndex = tmGeneratorLines[1].firstCharacterIndex; var nextLineText = contentText.Substring(nextLineTextIndex); // 現在の行のセット textComponent.text = contentText.Substring(0, nextLineTextIndex); if (0 < textComponent.transform.childCount) { for (var i = 0; i < textComponent.transform.childCount; i++) { var childRectTrans = textComponent.transform.GetChild(i).GetComponent <RectTransform>(); childRectTrans.pivot = new Vector2(0, 1); childRectTrans.anchorMin = new Vector2(0, 1); childRectTrans.anchorMax = new Vector2(0, 1); childRectTrans.anchoredPosition = Vector2.zero; } } textComponent.rectTransform.anchoredPosition = new Vector2(originX, originY); textComponent.rectTransform.sizeDelta = new Vector2(currentFirstLineWidth, currentFirstLineHeight); var childOriginX = originX; var currentTotalLineHeight = LineFeed <LTRootElement>(ref originX, ref originY, currentFirstLineHeight, ref currentLineMaxHeight, ref lineContents, ref wrappedSize); // 文字コンテンツの高さ分改行する // 次の行のコンテンツをこのコンテンツの子として生成するが、レイアウトまでを行わず次の行の起点の計算を行う。 // ここで全てを計算しない理由は、この処理の結果、複数種類のレイアウトが発生するため、ここで全てを書かない方が変えやすい。 { // 末尾でgotoを使って次の行頭からのコンテンツの設置に行くので、計算に使う残り幅をビュー幅へとセットする。 restWidth = viewWidth; // 次の行のコンテンツを入れる var nextLineTextElement = textElement.GenerateGO(nextLineText).GetComponent <T>(); nextLineTextElement.transform.SetParent(textElement.transform, false); // 消しやすくするため、この新規コンテンツを子にする // xは-に、yは親の直下に置く。yは特に、「親が親の行上でどのように配置されたのか」を加味する必要がある。 // 例えば親行の中で親が最大の背の高さのコンテンツでない場合、改行すべき値は 親の背 + (行の背 - 親の背)/2 になる。 var yPosFromLinedParentY = -( // 下向きがマイナスな座標系なのでマイナス currentFirstLineHeight // 現在の文字の高さと行の高さを比較し、文字の高さ + 上側の差の高さ(差/2)を足して返す。 + ( currentTotalLineHeight - currentFirstLineHeight ) / 2 ); // X表示位置を原点にずらす、Yは次のコンテンツの開始Y位置 = LineFeedで変更された親の位置に依存し、親の位置からoriginYを引いた値になる。 var newTailTextElementRectTrans = nextLineTextElement.GetComponent <RectTransform>(); newTailTextElementRectTrans.anchoredPosition = new Vector2(-childOriginX, yPosFromLinedParentY); // テキスト特有の継続したコンテンツ扱いする。 continueContent = true; // 生成したコンテンツを次の行の要素へと追加する lineContents.Add(newTailTextElementRectTrans); // 上書きを行う textElement = nextLineTextElement; contentText = nextLineText; goto NextLine; } } case TextLayoutStatus.HeadAndMulti: { // このコンテンツは矩形で、行揃えの影響を受けないため、明示的に行から取り除く。 lineContents.RemoveAt(lineContents.Count - 1); var lineCount = textInfos.lineCount; var lineStrs = new string[lineCount]; var totalHeight = 0f; for (var j = 0; j < lineCount; j++) { var lInfo = textInfos.lineInfo[j]; totalHeight += lInfo.lineHeight; // ここで、含まれている絵文字の数がわかれば、そのぶんを後ろに足すことで文字切れを回避できそう、、ではある、、 lineStrs[j] = contentText.Substring(lInfo.firstCharacterIndex, lInfo.lastCharacterIndex - lInfo.firstCharacterIndex + 1); } // 矩形になるテキスト = 最終行を取り除いたテキストを得る var rectTexts = new string[lineStrs.Length - 1]; for (var i = 0; i < rectTexts.Length; i++) { rectTexts[i] = lineStrs[i]; } // 最終行のテキストを得る var lastLineText = lineStrs[lineStrs.Length - 1]; // rectの高さの取得 var lastLineHeight = textInfos.lineInfo[lineCount - 1].lineHeight; var rectHeight = totalHeight - lastLineHeight; // 改行コードを入れ、複数行での表示をいい感じにする。 textComponent.text = string.Join("\n", rectTexts); if (0 < textComponent.transform.childCount) { for (var i = 0; i < textComponent.transform.childCount; i++) { var childRectTrans = textComponent.transform.GetChild(i).GetComponent <RectTransform>(); childRectTrans.pivot = new Vector2(0, 1); childRectTrans.anchorMin = new Vector2(0, 1); childRectTrans.anchorMax = new Vector2(0, 1); childRectTrans.anchoredPosition = Vector2.zero; } } textComponent.rectTransform.sizeDelta = new Vector2(restWidth, rectHeight); // 幅の最大値を取得 var max = Mathf.Max(textComponent.rectTransform.sizeDelta.x, textComponent.preferredWidth); // wrappedな幅の更新 wrappedSize.x = Mathf.Max(wrappedSize.x, max); // なんらかの続きの文字コンテンツである場合、そのコンテンツの子になっているので位置情報を調整しない。最終行を分割する。 if (continueContent) { // 別のコンテンツから継続している行はじめの処理なので、子をセットする前にここまでの分の改行を行う。 LineFeed <LTRootElement>(ref originX, ref originY, rectHeight, ref currentLineMaxHeight, ref lineContents, ref wrappedSize); // 末尾でgotoを使って次の行頭からのコンテンツの設置に行くので、計算に使う残り幅をビュー幅へとセットする。 restWidth = viewWidth; // 最終行のコンテンツを入れる var nextLineTextElement = textElement.GenerateGO(lastLineText).GetComponent <T>(); nextLineTextElement.transform.SetParent(textElement.transform.parent, false); // 消しやすくするため、この新規コンテンツを現在の要素の親の子にする // 次の行の行頭になる = 続いている要素と同じxを持つ var childX = textComponent.rectTransform.anchoredPosition.x; // yは親の分移動する var childY = textComponent.rectTransform.anchoredPosition.y - rectHeight; var newBrotherTailTextElementRectTrans = nextLineTextElement.GetComponent <RectTransform>(); newBrotherTailTextElementRectTrans.anchoredPosition = new Vector2(childX, childY); // 継続させる continueContent = true; // 生成したコンテンツを次の行の要素へと追加する lineContents.Add(newBrotherTailTextElementRectTrans); // 上書きを行う textElement = nextLineTextElement; contentText = lastLineText; goto NextLine; } // 誰かの子ではないので、独自に自分の位置をセットする textComponent.rectTransform.anchoredPosition = new Vector2(originX, originY); // 最終行のコンテンツを入れる var newTextElement = textElement.GenerateGO(lastLineText).GetComponent <T>(); newTextElement.transform.SetParent(rectTrans, false); // 消しやすくするため、この新規コンテンツを現在の要素の子にする // 残りの行のサイズは最大化する restWidth = viewWidth; // 次の行の行頭になる originX = 0; // yは親の分移動する originY -= rectHeight; { // 新規オブジェクトはそのy位置を親コンテンツの高さを加えた値にセットする。 var newTailTextElementRectTrans = newTextElement.GetComponent <RectTransform>(); newTailTextElementRectTrans.anchoredPosition = new Vector2(originX, -rectHeight); // 残りのデータをテキスト特有の継続したコンテンツ扱いする。 continueContent = true; // 生成したコンテンツを次の行の要素へと追加する lineContents.Add(newTailTextElementRectTrans); textElement = newTextElement; contentText = lastLineText; goto NextLine; } } case TextLayoutStatus.OutOfViewAndSingle: { // 1行ぶんのみのコンテンツで、行末が溢れている。入るように要素を切り、残りを継続してHeadAndSingleとして処理する。 // 超過している幅を収めるために、1文字ぶんだけ引いた文字を使ってレイアウトを行う。 var index = contentText.Length - 1; var firstLineText = contentText.Substring(0, index); var restText = contentText.Substring(index); // 現在の行のセット textComponent.text = firstLineText; if (0 < textComponent.transform.childCount) { for (var i = 0; i < textComponent.transform.childCount; i++) { var childRectTrans = textComponent.transform.GetChild(i).GetComponent <RectTransform>(); childRectTrans.pivot = new Vector2(0, 1); childRectTrans.anchorMin = new Vector2(0, 1); childRectTrans.anchorMax = new Vector2(0, 1); childRectTrans.anchoredPosition = Vector2.zero; } } textComponent.rectTransform.anchoredPosition = new Vector2(originX, originY); textComponent.rectTransform.sizeDelta = new Vector2(currentFirstLineWidth, currentFirstLineHeight); var childOriginX = originX; var currentTotalLineHeight = LineFeed <LTRootElement>(ref originX, ref originY, currentFirstLineHeight, ref currentLineMaxHeight, ref lineContents, ref wrappedSize); // 文字コンテンツの高さ分改行する // 次の行のコンテンツをこのコンテンツの子として生成するが、レイアウトまでを行わず次の行の起点の計算を行う。 // ここで全てを計算しない理由は、この処理の結果、複数種類のレイアウトが発生するため、ここで全てを書かない方が変えやすい。 { // 末尾でgotoを使って次の行頭からのコンテンツの設置に行くので、計算に使う残り幅をビュー幅へとセットする。 restWidth = viewWidth; // 次の行のコンテンツを入れる var nextLineTextElement = textElement.GenerateGO(restText).GetComponent <T>(); nextLineTextElement.transform.SetParent(textElement.transform, false); // 消しやすくするため、この新規コンテンツを子にする // xは-に、yは親の直下に置く。yは特に、「親が親の行上でどのように配置されたのか」を加味する必要がある。 // 例えば親行の中で親が最大の背の高さのコンテンツでない場合、改行すべき値は 親の背 + (行の背 - 親の背)/2 になる。 var yPosFromLinedParentY = -( // 下向きがマイナスな座標系なのでマイナス currentFirstLineHeight // 現在の文字の高さと行の高さを比較し、文字の高さ + 上側の差の高さ(差/2)を足して返す。 + ( currentTotalLineHeight - currentFirstLineHeight ) / 2 ); // X表示位置を原点にずらす、Yは次のコンテンツの開始Y位置 = LineFeed<LTAsyncRootElement>で変更された親の位置に依存し、親の位置からoriginYを引いた値になる。 var newTailTextElementRectTrans = nextLineTextElement.GetComponent <RectTransform>(); newTailTextElementRectTrans.anchoredPosition = new Vector2(-childOriginX, yPosFromLinedParentY); // テキスト特有の継続したコンテンツ扱いする。 continueContent = true; // 生成したコンテンツを次の行の要素へと追加する lineContents.Add(newTailTextElementRectTrans); // 上書きを行う textElement = nextLineTextElement; contentText = restText; goto NextLine; } } case TextLayoutStatus.OutOfViewAndMulti: { // 複数行があるのが確定していて、最初の行の内容が溢れている。入るように要素を切り、残りを継続してHeadAndMultiとして処理する。 // 複数行が既に存在するのが確定しているので、次の行のコンテンツをそのまま取得、分割する。 var nextLineTextIndex = tmGeneratorLines[1].firstCharacterIndex; // 超過している幅を収めるために、1文字ぶんだけ引いた文字を使ってレイアウトを行う。 var index = nextLineTextIndex - 1; var firstLineText = contentText.Substring(0, index); var restText = contentText.Substring(index); // 現在の行のセット textComponent.text = firstLineText; if (0 < textComponent.transform.childCount) { for (var i = 0; i < textComponent.transform.childCount; i++) { var childRectTrans = textComponent.transform.GetChild(i).GetComponent <RectTransform>(); childRectTrans.pivot = new Vector2(0, 1); childRectTrans.anchorMin = new Vector2(0, 1); childRectTrans.anchorMax = new Vector2(0, 1); childRectTrans.anchoredPosition = Vector2.zero; } } textComponent.rectTransform.anchoredPosition = new Vector2(originX, originY); textComponent.rectTransform.sizeDelta = new Vector2(currentFirstLineWidth, currentFirstLineHeight); var childOriginX = originX; var currentTotalLineHeight = LineFeed <LTRootElement>(ref originX, ref originY, currentFirstLineHeight, ref currentLineMaxHeight, ref lineContents, ref wrappedSize); // 文字コンテンツの高さ分改行する // 次の行のコンテンツをこのコンテンツの子として生成するが、レイアウトまでを行わず次の行の起点の計算を行う。 // ここで全てを計算しない理由は、この処理の結果、複数種類のレイアウトが発生するため、ここで全てを書かない方が変えやすい。 { // 末尾でgotoを使って次の行頭からのコンテンツの設置に行くので、計算に使う残り幅をビュー幅へとセットする。 restWidth = viewWidth; // 次の行のコンテンツを入れる var nextLineTextElement = textElement.GenerateGO(restText).GetComponent <T>(); nextLineTextElement.transform.SetParent(textElement.transform, false); // 消しやすくするため、この新規コンテンツを子にする // xは-に、yは親の直下に置く。yは特に、「親が親の行上でどのように配置されたのか」を加味する必要がある。 // 例えば親行の中で親が最大の背の高さのコンテンツでない場合、改行すべき値は 親の背 + (行の背 - 親の背)/2 になる。 var yPosFromLinedParentY = -( // 下向きがマイナスな座標系なのでマイナス currentFirstLineHeight // 現在の文字の高さと行の高さを比較し、文字の高さ + 上側の差の高さ(差/2)を足して返す。 + ( currentTotalLineHeight - currentFirstLineHeight ) / 2 ); // X表示位置を原点にずらす、Yは次のコンテンツの開始Y位置 = LineFeed<LTAsyncRootElement>で変更された親の位置に依存し、親の位置からoriginYを引いた値になる。 var newTailTextElementRectTrans = nextLineTextElement.GetComponent <RectTransform>(); newTailTextElementRectTrans.anchoredPosition = new Vector2(-childOriginX, yPosFromLinedParentY); // テキスト特有の継続したコンテンツ扱いする。 continueContent = true; // 生成したコンテンツを次の行の要素へと追加する lineContents.Add(newTailTextElementRectTrans); // 上書きを行う textElement = nextLineTextElement; contentText = restText; goto NextLine; } } } }
// This function parses through the Char[] to determine how many characters will be visible. It then makes sure the arrays are large enough for all those characters. protected override int SetArraySizes(int[] chars) { //Debug.Log("*** SetArraySizes() ***"); int tagEnd = 0; int spriteCount = 0; m_totalCharacterCount = 0; m_isUsingBold = false; m_isParsingText = false; m_style = m_fontStyle; //m_fontWeightInternal = (m_style & FontStyles.Bold) == FontStyles.Bold ? 700 : m_fontWeight; //m_fontWeightStack.SetDefault(m_fontWeightInternal); m_currentFontAsset = m_fontAsset; m_currentMaterial = m_sharedMaterial; m_currentMaterialIndex = 0; m_materialReferenceStack.SetDefault(new MaterialReference(0, m_currentFontAsset, null, m_currentMaterial, m_padding)); m_materialReferenceIndexLookup.Clear(); MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup); if (m_textInfo == null) m_textInfo = new TMP_TextInfo(); m_textElementType = TMP_TextElementType.Character; // Parsing XML tags in the text for (int i = 0; chars[i] != 0; i++) { //Make sure the characterInfo array can hold the next text element. if (m_textInfo.characterInfo == null || m_totalCharacterCount >= m_textInfo.characterInfo.Length) TMP_TextInfo.Resize(ref m_textInfo.characterInfo, m_totalCharacterCount + 1, true); int c = chars[i]; // PARSE XML TAGS #region PARSE XML TAGS if (m_isRichText && c == 60) // if Char '<' { int prev_MaterialIndex = m_currentMaterialIndex; // 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; if (m_textElementType == TMP_TextElementType.Sprite) { m_materialReferences[m_currentMaterialIndex].referenceCount += 1; m_textInfo.characterInfo[m_totalCharacterCount].character = (char)(57344 + m_spriteIndex); m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; // Restore element type and material index to previous values. m_textElementType = TMP_TextElementType.Character; m_currentMaterialIndex = prev_MaterialIndex; spriteCount += 1; m_totalCharacterCount += 1; } continue; } } #endregion bool isUsingFallback = false; bool isUsingAlternativeTypeface = false; TMP_Glyph glyph; TMP_FontAsset prev_fontAsset = m_currentFontAsset; Material prev_material = m_currentMaterial; int prev_materialIndex = m_currentMaterialIndex; // Handle Font Styles like LowerCase, UpperCase and SmallCaps. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles if (m_textElementType == TMP_TextElementType.Character) { if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase) { // If this character is lowercase, switch to uppercase. if (char.IsLower((char)c)) c = char.ToUpper((char)c); } else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase) { // If this character is uppercase, switch to lowercase. if (char.IsUpper((char)c)) c = char.ToLower((char)c); } else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps) { // Only convert lowercase characters to uppercase. if (char.IsLower((char)c)) c = char.ToUpper((char)c); } } #endregion // Lookup the Glyph data for each character and cache it. #region LOOKUP GLYPH m_currentFontAsset.characterDictionary.TryGetValue(c, out glyph); if (glyph == null) { // Check Fallback Font Assets if (m_settings != null && m_settings.fallbackFontAssets != null) { // Iterate through each Fallback Font Asset looking for the missing character. for (int y = 0; y < m_settings.fallbackFontAssets.Count; y++) { TMP_FontAsset fontAsset = m_settings.fallbackFontAssets[y]; if (fontAsset == null) continue; if (fontAsset.characterDictionary.TryGetValue(c, out glyph)) { isUsingFallback = true; m_currentFontAsset = fontAsset; m_currentMaterial = fontAsset.material; m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, fontAsset, m_materialReferences, m_materialReferenceIndexLookup); break; } } } // Check if Lowercase or Uppercase variant of the character is available. if (glyph == null) { if (char.IsLower((char)c)) { if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToUpper((char)c), out glyph)) c = chars[i] = char.ToUpper((char)c); } else if (char.IsUpper((char)c)) { if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToLower((char)c), out glyph)) c = chars[i] = char.ToLower((char)c); } } // Still don't have a replacement? if (glyph == null) { m_currentFontAsset.characterDictionary.TryGetValue(9633, out glyph); if (glyph != null) { if (!m_warningsDisabled) Debug.LogWarning("Character with ASCII value of " + c + " was not found in the Font Asset Glyph Table.", this); // Replace the missing character by square missing glyph character c = chars[i] = 9633; } else { // Get a reference to ARIAL SDF TMP_FontAsset fontAsset = TMP_FontAsset.defaultFontAsset; if (fontAsset != null && fontAsset.characterDictionary.TryGetValue(9633, out glyph)) { // Use Square Missing Glyph from ARIAL SDF if (!m_warningsDisabled) Debug.LogWarning("Character with ASCII value of " + c + " was not found in the Font Asset Glyph Table.", this); c = chars[i] = 9633; isUsingFallback = true; m_currentFontAsset = fontAsset; m_currentMaterial = fontAsset.material; m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, fontAsset, m_materialReferences, m_materialReferenceIndexLookup); } } } } #endregion m_textInfo.characterInfo[m_totalCharacterCount].textElement = glyph; m_textInfo.characterInfo[m_totalCharacterCount].character = (char)c; m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].material = m_currentMaterial; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; if (!char.IsWhiteSpace((char)c)) { // HANDLE FONT WEIGHTS #region FONT WEIGHTS //if (m_style == FontStyles.Bold || m_fontStyle == FontStyles.Bold) //{ // Debug.Log("Typeface is bold."); //} //else if (m_style == FontStyles.Italic || m_fontStyle == FontStyles.Italic) //{ // Debug.Log("Typeface is italic."); //} #endregion m_materialReferences[m_currentMaterialIndex].referenceCount += 1; if (isUsingAlternativeTypeface) m_currentMaterialIndex = prev_materialIndex; // Restore previous font asset and material if fallback font was used. if (isUsingFallback) { m_currentFontAsset = prev_fontAsset; m_currentMaterial = prev_material; m_currentMaterialIndex = prev_materialIndex; } } m_totalCharacterCount += 1; } // Save material and sprite count. m_textInfo.spriteCount = spriteCount; int materialCount = m_textInfo.materialCount = m_materialReferenceIndexLookup.Count; // Check if we need to resize the MeshInfo array for handling different materials. if (materialCount > m_textInfo.meshInfo.Length) TMP_TextInfo.Resize(ref m_textInfo.meshInfo, materialCount, false); // Iterate through the material references to set the mesh buffer allocations for (int i = 0; i < materialCount; i++) { // Add new sub text object for each material reference if (i > 0) { if (m_subTextObjects[i] == null) { m_subTextObjects[i] = TMP_SubMesh.AddSubTextObject(this, m_materialReferences[i]); // Not sure this is necessary m_textInfo.meshInfo[i].vertices = null; } // Check if the material has changed. if (m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.GetInstanceID() != m_materialReferences[i].material.GetInstanceID()) { bool isDefaultMaterial = m_materialReferences[i].isDefaultMaterial; m_subTextObjects[i].isDefaultMaterial = isDefaultMaterial; // Assign new material if we are not using the default material or if the font asset has changed. if (!isDefaultMaterial || m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.mainTexture.GetInstanceID() != m_materialReferences[i].material.mainTexture.GetInstanceID()) m_subTextObjects[i].sharedMaterial = m_materialReferences[i].material; } } int referenceCount = m_materialReferences[i].referenceCount; // Check to make sure our buffers allocations can accommodate the required text elements. if (m_textInfo.meshInfo[i].vertices == null || m_textInfo.meshInfo[i].vertices.Length < referenceCount * 4) { if (m_textInfo.meshInfo[i].vertices == null) { if (i == 0) m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_mesh, referenceCount + 1); else m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_subTextObjects[i].mesh, referenceCount + 1); } else m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.NextPowerOfTwo(referenceCount)); } } // Clean up unused SubMeshes for (int i = materialCount; i < m_subTextObjects.Length + 1 && m_subTextObjects[i] != null; i++) { if (i < m_textInfo.meshInfo.Length) m_textInfo.meshInfo[i].ClearUnusedVertices(0, true); } return m_totalCharacterCount; }
/// <summary> /// Plays the typewriter effect. /// </summary> public virtual IEnumerator Play(int fromIndex) { if (unprocessedText != null && (textComponent != null) && (charactersPerSecond > 0)) { if (waitOneFrameBeforeStarting) { yield return(null); } fromIndex = StripRPGMakerCodes(Tools.StripTags(unprocessedText.Substring(0, fromIndex))).Length; if (runtimeAudioSource != null) { runtimeAudioSource.clip = audioClip; } onBegin.Invoke(); paused = false; float delay = 1 / charactersPerSecond; float lastTime = DialogueTime.time; float elapsed = fromIndex / charactersPerSecond; maxVisibleCharacters = fromIndex; yield return(null); maxVisibleCharacters = fromIndex; TMPro.TMP_TextInfo textInfo = textComponent.textInfo; var parsedText = textComponent.GetParsedText(); int totalVisibleCharacters = textInfo.characterCount; // Get # of Visible Character in text object charactersTyped = fromIndex; int skippedCharacters = 0; while (charactersTyped < totalVisibleCharacters) { if (!paused) { var deltaTime = DialogueTime.time - lastTime; elapsed += deltaTime; var goal = (elapsed * charactersPerSecond) + skippedCharacters; while (charactersTyped < goal) { if (rpgMakerTokens.ContainsKey(charactersTyped)) { var tokens = rpgMakerTokens[charactersTyped]; for (int i = 0; i < tokens.Count; i++) { var token = tokens[i]; switch (token) { case RPGMakerTokenType.QuarterPause: yield return(DialogueTime.WaitForSeconds(quarterPauseDuration)); break; case RPGMakerTokenType.FullPause: yield return(DialogueTime.WaitForSeconds(fullPauseDuration)); break; case RPGMakerTokenType.SkipToEnd: charactersTyped = totalVisibleCharacters - 1; break; case RPGMakerTokenType.InstantOpen: var close = false; while (!close && charactersTyped < totalVisibleCharacters) { charactersTyped++; skippedCharacters++; if (rpgMakerTokens.ContainsKey(charactersTyped) && rpgMakerTokens[charactersTyped].Contains(RPGMakerTokenType.InstantClose)) { close = true; } } break; } } } var typedCharacter = (0 <= charactersTyped && charactersTyped < parsedText.Length) ? parsedText[charactersTyped] : ' '; if (charactersTyped < totalVisibleCharacters && !IsSilentCharacter(typedCharacter)) { PlayCharacterAudio(typedCharacter); } onCharacter.Invoke(); charactersTyped++; maxVisibleCharacters = charactersTyped; if (IsFullPauseCharacter(typedCharacter)) { yield return(DialogueTime.WaitForSeconds(fullPauseDuration)); } else if (IsQuarterPauseCharacter(typedCharacter)) { yield return(DialogueTime.WaitForSeconds(quarterPauseDuration)); } } } maxVisibleCharacters = charactersTyped; HandleAutoScroll(); //---Uncomment the line below to debug: //Debug.Log(textComponent.text.Substring(0, charactersTyped).Replace("<", "[").Replace(">", "]") + " (typed=" + charactersTyped + ")"); lastTime = DialogueTime.time; var delayTime = DialogueTime.time + delay; int delaySafeguard = 0; while (DialogueTime.time < delayTime && delaySafeguard < 999) { delaySafeguard++; yield return(null); } } } Stop(); }
/// Show a line of dialogue, gradually public override IEnumerator RunLine(Yarn.Line line) { lineText.gameObject.SetActive(false); lineText.gameObject.SetActive(true); // Reset text customTagHandler.StopAllCoroutines(); customTagHandler.clearClones(); prevColors.Clear(); lineText.SetText(customTagHandler.ParseForCustomTags(YarnRTFToTMP(line.text))); lineText.ForceMeshUpdate(); customTagHandler.ApplyTagEffects(); // Set up teletype by setting alpha to 0 TMPro.TMP_Text m_TextComponent = lineText.GetComponent <TMPro.TMP_Text>(); TMPro.TMP_TextInfo textInfo = m_TextComponent.textInfo; while (textInfo.characterCount == 0) { yield return(new WaitForSeconds(0.25f)); } Color32[] newVertexColors; for (int currentCharacter = 0; currentCharacter < textInfo.characterCount; currentCharacter++) { int materialIndex = textInfo.characterInfo[currentCharacter].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; int vertexIndex = textInfo.characterInfo[currentCharacter].vertexIndex; // Save prev color if (textInfo.characterInfo[currentCharacter].isVisible) { for (int j = 0; j < 4; j++) { prevColors.Add(textInfo.meshInfo[materialIndex].colors32[vertexIndex + j]); } } else { for (int j = 0; j < 4; j++) { prevColors.Add(new Color32(0, 0, 0, 0)); } } // Set color to transparent if (textInfo.characterInfo[currentCharacter].isVisible) { for (int j = 0; j < 4; j++) { newVertexColors[vertexIndex + j] = new Color32(textInfo.meshInfo[materialIndex].colors32[vertexIndex + j].r, textInfo.meshInfo[materialIndex].colors32[vertexIndex + j].g, textInfo.meshInfo[materialIndex].colors32[vertexIndex + j].b, 0); } m_TextComponent.UpdateVertexData(TMPro.TMP_VertexDataUpdateFlags.Colors32); } } if (textSpeed > 0.0f) { // Display the line one character at a time for (int i = 0; i < textInfo.characterCount; i++) { int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; int vertexIndex = textInfo.characterInfo[i].vertexIndex; if (textInfo.characterInfo[i].isVisible) { for (int j = 0; j < 4; j++) { newVertexColors[vertexIndex + j] = prevColors[4 * i + j]; } m_TextComponent.UpdateVertexData(TMPro.TMP_VertexDataUpdateFlags.Colors32); } yield return(new WaitForSeconds(textSpeed)); } } else { // Display the entire line immediately if textSpeed <= 0 for (int currentCharacter = 0; currentCharacter < textInfo.characterCount; currentCharacter++) { int materialIndex = textInfo.characterInfo[currentCharacter].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; int vertexIndex = textInfo.characterInfo[currentCharacter].vertexIndex; // Set color back to the color it is supposed to be if (textInfo.characterInfo[currentCharacter].isVisible) { for (int j = 0; j < 4; j++) { newVertexColors[vertexIndex + j] = prevColors[4 * currentCharacter + j]; } m_TextComponent.UpdateVertexData(TMPro.TMP_VertexDataUpdateFlags.Colors32); } } } // Reset custom tag runner customTagHandler.ClearParsedTags(); // Show the 'press any key' prompt when done, if we have one if (continuePrompt != null) { continuePrompt.SetActive(true); } // Wait for trigger press while (gameManager.LH_Trigger == false && gameManager.RH_Trigger == false) { yield return(null); } // Avoid skipping lines if textSpeed == 0 yield return(new WaitForEndOfFrame()); // Hide the text and prompt lineText.gameObject.SetActive(false); if (continuePrompt != null) { continuePrompt.SetActive(false); } }
// This function parses through the Char[] to determine how many characters will be visible. It then makes sure the arrays are large enough for all those characters. protected override int SetArraySizes(int[] chars) { //Debug.Log("*** SetArraySizes() ***"); #if PROFILE_ON Profiler.BeginSample("SetArraySizes"); #endif int tagEnd = 0; int spriteCount = 0; m_totalCharacterCount = 0; m_isUsingBold = false; m_isParsingText = false; tag_NoParsing = false; m_style = m_fontStyle; m_fontWeightInternal = (m_style & FontStyles.Bold) == FontStyles.Bold ? 700 : m_fontWeight; m_fontWeightStack.SetDefault(m_fontWeightInternal); m_currentFontAsset = m_fontAsset; m_currentMaterial = m_sharedMaterial; m_currentMaterialIndex = 0; m_materialReferenceStack.SetDefault(new MaterialReference(0, m_currentFontAsset, null, m_currentMaterial, m_padding)); m_materialReferenceIndexLookup.Clear(); MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup); if (m_textInfo == null) m_textInfo = new TMP_TextInfo(); m_textElementType = TMP_TextElementType.Character; // Parsing XML tags in the text for (int i = 0; chars[i] != 0; i++) { //Make sure the characterInfo array can hold the next text element. if (m_textInfo.characterInfo == null || m_totalCharacterCount >= m_textInfo.characterInfo.Length) TMP_TextInfo.Resize(ref m_textInfo.characterInfo, m_totalCharacterCount + 1, true); int c = chars[i]; // PARSE XML TAGS #region PARSE XML TAGS if (m_isRichText && c == 60) // if Char '<' { int prev_MaterialIndex = m_currentMaterialIndex; // 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; if (m_textElementType == TMP_TextElementType.Sprite) { m_materialReferences[m_currentMaterialIndex].referenceCount += 1; m_textInfo.characterInfo[m_totalCharacterCount].character = (char)(57344 + m_spriteIndex); m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; // Restore element type and material index to previous values. m_textElementType = TMP_TextElementType.Character; m_currentMaterialIndex = prev_MaterialIndex; spriteCount += 1; m_totalCharacterCount += 1; } continue; } } #endregion bool isUsingFallback = false; bool isUsingAlternativeTypeface = false; TMP_Glyph glyph; TMP_FontAsset tempFontAsset; TMP_FontAsset prev_fontAsset = m_currentFontAsset; Material prev_material = m_currentMaterial; int prev_materialIndex = m_currentMaterialIndex; // Handle Font Styles like LowerCase, UpperCase and SmallCaps. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles if (m_textElementType == TMP_TextElementType.Character) { if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase) { // If this character is lowercase, switch to uppercase. if (char.IsLower((char)c)) c = char.ToUpper((char)c); } else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase) { // If this character is uppercase, switch to lowercase. if (char.IsUpper((char)c)) c = char.ToLower((char)c); } else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps) { // Only convert lowercase characters to uppercase. if (char.IsLower((char)c)) c = char.ToUpper((char)c); } } #endregion // Handling of font weights. #region HANDLING OF FONT WEIGHT tempFontAsset = GetFontAssetForWeight(m_fontWeightInternal); if (tempFontAsset != null) { isUsingFallback = true; isUsingAlternativeTypeface = true; m_currentFontAsset = tempFontAsset; m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material.GetTexture(ShaderUtilities.ID_MainTex)); //m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFontAsset, m_materialReferences, m_materialReferenceIndexLookup); } #endregion // Lookup the Glyph data for each character and cache it. #region LOOKUP GLYPH if (m_currentFontAsset.characterDictionary.TryGetValue(c, out glyph) == false) { // Check current font asset font fallback list. if (m_currentFontAsset.fallbackFontAssets != null && m_currentFontAsset.fallbackFontAssets.Count > 0) { // Iterate through each Fallback Font Asset looking for the missing character. for (int y = 0; y < m_currentFontAsset.fallbackFontAssets.Count; y++) { tempFontAsset = m_currentFontAsset.fallbackFontAssets[y]; if (tempFontAsset == null) continue; if (tempFontAsset.characterDictionary.TryGetValue(c, out glyph)) { isUsingFallback = true; m_currentFontAsset = tempFontAsset; m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material.GetTexture(ShaderUtilities.ID_MainTex)); //m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFontAsset, m_materialReferences, m_materialReferenceIndexLookup); break; } } } // Check TMP Settings font asset fallback list. if (glyph == null) { if (TMP_Settings.fallbackFontAssets != null && TMP_Settings.fallbackFontAssets.Count > 0) { // Iterate through each Fallback Font Asset looking for the missing character. for (int y = 0; y < TMP_Settings.fallbackFontAssets.Count; y++) { tempFontAsset = TMP_Settings.fallbackFontAssets[y]; if (tempFontAsset == null) continue; if (tempFontAsset.characterDictionary.TryGetValue(c, out glyph)) { isUsingFallback = true; m_currentFontAsset = tempFontAsset; m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material.GetTexture(ShaderUtilities.ID_MainTex)); //m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFontAsset, m_materialReferences, m_materialReferenceIndexLookup); break; } } } } // Check if Lowercase or Uppercase variant of the character is available. if (glyph == null) { if (char.IsLower((char)c)) { if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToUpper((char)c), out glyph)) c = chars[i] = char.ToUpper((char)c); } else if (char.IsUpper((char)c)) { if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToLower((char)c), out glyph)) c = chars[i] = char.ToLower((char)c); } } // Since the missing character is still unavailable, try replacing it by TMP Settings Missing Glyph or Square (9633) character. if (glyph == null) { // Check for the missing glyph character in the currently assigned font asset. int altGlyphCode = TMP_Settings.missingGlyphCharacter == 0 ? 9633 : TMP_Settings.missingGlyphCharacter; if (m_currentFontAsset.characterDictionary.TryGetValue(altGlyphCode, out glyph)) { if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Character with ASCII value of " + c + " was not found in the Font Asset Glyph Table.", this); // Replace the missing character by square missing glyph character c = chars[i] = altGlyphCode; } else { // Check for the missing glyph character in the Font Fallback list. if (TMP_Settings.fallbackFontAssets != null && TMP_Settings.fallbackFontAssets.Count > 0) { // Iterate through each Fallback Font Asset looking for the missing character. for (int y = 0; y < TMP_Settings.fallbackFontAssets.Count; y++) { tempFontAsset = TMP_Settings.fallbackFontAssets[y]; if (tempFontAsset == null) continue; if (tempFontAsset.characterDictionary.TryGetValue(altGlyphCode, out glyph)) { // Use Square Missing Glyph from Default Font Asset. if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Character with ASCII value of " + c + " was not found in the Font Asset Glyph Table.", this); c = chars[i] = altGlyphCode; isUsingFallback = true; m_currentFontAsset = tempFontAsset; m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material.GetTexture(ShaderUtilities.ID_MainTex)); //m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFontAsset, m_materialReferences, m_materialReferenceIndexLookup); break; } } } // Check for the missing glyph character in the Default Font Asset assigned in the TMP Settings file. if (glyph == null) { tempFontAsset = TMP_Settings.GetFontAsset(); if (tempFontAsset != null && tempFontAsset.characterDictionary.TryGetValue(altGlyphCode, out glyph)) { // Use Square Missing Glyph from Default Font Asset. if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Character with ASCII value of " + c + " was not found in the Font Asset Glyph Table.", this); c = chars[i] = altGlyphCode; isUsingFallback = true; m_currentFontAsset = tempFontAsset; m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material.GetTexture(ShaderUtilities.ID_MainTex)); //m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFontAsset, m_materialReferences, m_materialReferenceIndexLookup); } else { // Get a reference to ARIAL SDF tempFontAsset = TMP_FontAsset.defaultFontAsset; if (tempFontAsset != null && tempFontAsset.characterDictionary.TryGetValue(altGlyphCode, out glyph)) { // Use Square Missing Glyph from ARIAL SDF if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Character with ASCII value of " + c + " was not found in the Font Asset Glyph Table.", this); c = chars[i] = altGlyphCode; isUsingFallback = true; m_currentFontAsset = tempFontAsset; m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material.GetTexture(ShaderUtilities.ID_MainTex)); //m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFontAsset, m_materialReferences, m_materialReferenceIndexLookup); } else { // Replacing missing glyph by Space (32) since no suitable replacement has been found. if (m_currentFontAsset.characterDictionary.TryGetValue(32, out glyph)) { // Use Space (32) Glyph if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Character with ASCII value of " + c + " was not found in the Font Asset Glyph Table. It was replaced by a space.", this); c = chars[i] = 32; } } } } } } } #endregion m_textInfo.characterInfo[m_totalCharacterCount].textElement = glyph; m_textInfo.characterInfo[m_totalCharacterCount].isUsingAlternateTypeface = isUsingAlternativeTypeface; m_textInfo.characterInfo[m_totalCharacterCount].character = (char)c; m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].material = m_currentMaterial; if (isUsingFallback) m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup); m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; m_materialReferences[m_currentMaterialIndex].isFallbackFont = isUsingFallback; if (!char.IsWhiteSpace((char)c)) { m_materialReferences[m_currentMaterialIndex].referenceCount += 1; } // Restore previous font asset and material if fallback font was used. if (isUsingFallback) { m_currentFontAsset = prev_fontAsset; m_currentMaterial = prev_material; m_currentMaterialIndex = prev_materialIndex; } m_totalCharacterCount += 1; } // Save material and sprite count. m_textInfo.spriteCount = spriteCount; int materialCount = m_textInfo.materialCount = m_materialReferenceIndexLookup.Count; // Check if we need to resize the MeshInfo array for handling different materials. if (materialCount > m_textInfo.meshInfo.Length) TMP_TextInfo.Resize(ref m_textInfo.meshInfo, materialCount, false); // Resize CharacterInfo[] if allocations are excessive if (m_textInfo.characterInfo.Length - m_totalCharacterCount > 256) TMP_TextInfo.Resize(ref m_textInfo.characterInfo, Mathf.Max(m_totalCharacterCount + 1, 256), true); // Iterate through the material references to set the mesh buffer allocations for (int i = 0; i < materialCount; i++) { // Add new sub text object for each material reference if (i > 0) { if (m_subTextObjects[i] == null) { m_subTextObjects[i] = TMP_SubMeshUI.AddSubTextObject(this, m_materialReferences[i]); // Not sure this is necessary m_textInfo.meshInfo[i].vertices = null; } //else if (m_subTextObjects[i].gameObject.activeInHierarchy == false) // m_subTextObjects[i].gameObject.SetActive(true); // Make sure the pivots are synchronized if (m_rectTransform.pivot != m_subTextObjects[i].rectTransform.pivot) m_subTextObjects[i].rectTransform.pivot = m_rectTransform.pivot; // Check if the material has changed. if (m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.GetInstanceID() != m_materialReferences[i].material.GetInstanceID()) { bool isDefaultMaterial = m_materialReferences[i].isDefaultMaterial; m_subTextObjects[i].isDefaultMaterial = isDefaultMaterial; // Assign new material if we are not using the default material or if the font asset has changed. if (!isDefaultMaterial || m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.mainTexture.GetInstanceID() != m_materialReferences[i].material.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) { m_subTextObjects[i].sharedMaterial = m_materialReferences[i].material; m_subTextObjects[i].fontAsset = m_materialReferences[i].fontAsset; m_subTextObjects[i].spriteAsset = m_materialReferences[i].spriteAsset; } } // Check if we need to use a Fallback Material if (m_materialReferences[i].isFallbackFont) // && m_materialReferences[i].isDefaultMaterial) { Material newFallback = m_materialReferences[i].material; Material prevFallback = m_subTextObjects[i].m_fallbackMaterial; if (newFallback != prevFallback) { TMP_MaterialManager.RemoveFallbackMaterialReference(prevFallback); m_subTextObjects[i].m_fallbackMaterial = newFallback; TMP_MaterialManager.AddFallbackMaterialReference( newFallback); } } } int referenceCount = m_materialReferences[i].referenceCount; // Check to make sure our buffers allocations can accommodate the required text elements. if (m_textInfo.meshInfo[i].vertices == null || m_textInfo.meshInfo[i].vertices.Length < referenceCount * 4) { if (m_textInfo.meshInfo[i].vertices == null) { if (i == 0) m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_mesh, referenceCount + 1); else m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_subTextObjects[i].mesh, referenceCount + 1); } else m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.NextPowerOfTwo(referenceCount)); } else if (m_textInfo.meshInfo[i].vertices.Length - referenceCount * 4 > 1024) { // Resize vertex buffers if allocations are excessive. //Debug.Log("Reducing the size of the vertex buffers."); m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.Max(Mathf.NextPowerOfTwo(referenceCount), 256)); } } TMP_MaterialManager.CleanupFallbackMaterials(); // Clean up unused SubMeshes for (int i = materialCount; i < m_subTextObjects.Length + 1 && m_subTextObjects[i] != null; i++) { if (i < m_textInfo.meshInfo.Length) { m_subTextObjects[i].canvasRenderer.SetMesh(null); // TODO: Figure out a way to handle this without running into Unity's Rebuild loop issue. //m_subTextObjects[i].gameObject.SetActive(false); } } #if PROFILE_ON Profiler.EndSample(); #endif return m_totalCharacterCount; }
//private int loopCountB = 0; //private int loopCountC = 0; //private int loopCountD = 0; //private int loopCountE = 0; //[SerializeField] //private new Material m_MaskMaterial; protected override void Awake() { //Debug.Log("***** Awake() *****"); // Cache Reference to the Canvas m_canvas = this.canvas; m_isOrthographic = true; // Cache Reference to RectTransform. m_rectTransform = gameObject.GetComponent<RectTransform>(); if (m_rectTransform == null) m_rectTransform = gameObject.AddComponent<RectTransform>(); // Cache a reference to the CanvasRenderer. m_canvasRenderer = GetComponent<CanvasRenderer>(); if (m_canvasRenderer == null) m_canvasRenderer = gameObject.AddComponent<CanvasRenderer> (); if (m_mesh == null) { //Debug.Log("Creating new mesh."); m_mesh = new Mesh(); m_mesh.hideFlags = HideFlags.HideAndDontSave; //m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0)); } // Load TMP Settings for new text object instances. if (m_text == null) { 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; } // Load the font asset and assign material to renderer. LoadFontAsset(); // Load Default TMP StyleSheet TMP_StyleSheet.LoadDefaultStyleSheet(); // Allocate our initial buffers. m_char_buffer = new int[m_max_characters]; m_cached_TextElement = new TMP_Glyph(); m_isFirstAllocation = true; if (m_textInfo == null) m_textInfo = new TMP_TextInfo(this); // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen. if (m_fontAsset == null) { Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this); return; } // Set Defaults for Font Auto-sizing if (m_fontSizeMin == 0) m_fontSizeMin = m_fontSize / 2; if (m_fontSizeMax == 0) m_fontSizeMax = m_fontSize * 2; //// Set flags to ensure our text is parsed and redrawn. m_isInputParsingRequired = true; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isAwake = true; }