147 lines
6.3 KiB
C#
147 lines
6.3 KiB
C#
using TMPro;
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Base class for drawing a Text Pro text following a particular curve
|
|
/// </summary>
|
|
[ExecuteInEditMode]
|
|
public abstract class TMP_Curve : MonoBehaviour
|
|
{
|
|
/// <summary>
|
|
/// The text component of interest
|
|
/// </summary>
|
|
protected TMP_Text m_TextComponent;
|
|
|
|
/// <summary>
|
|
/// True if the text must be updated at this frame
|
|
/// </summary>
|
|
private bool m_forceUpdate;
|
|
public bool ForceUpdate
|
|
{
|
|
get { return m_forceUpdate; }
|
|
set { m_forceUpdate = value; }
|
|
}
|
|
|
|
private string cacheText = "";
|
|
|
|
/// <summary>
|
|
/// Awake
|
|
/// </summary>
|
|
private void Awake()
|
|
{
|
|
m_TextComponent = gameObject.GetComponent<TMP_Text>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// OnEnable
|
|
/// </summary>
|
|
private void OnEnable()
|
|
{
|
|
//every time the object gets enabled, we have to force a re-creation of the text mesh
|
|
m_forceUpdate = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update
|
|
/// </summary>
|
|
protected void Update()
|
|
{
|
|
//if the text and the parameters are the same of the old frame, don't waste time in re-computing everything
|
|
if (cacheText == m_TextComponent.text && !ParametersHaveChanged() && !m_TextComponent.havePropertiesChanged && !m_forceUpdate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cacheText = m_TextComponent.text;
|
|
m_forceUpdate = false;
|
|
|
|
//during the loop, vertices represents the 4 vertices of a single character we're analyzing,
|
|
//while matrix is the roto-translation matrix that will rotate and scale the characters so that they will
|
|
//follow the curve
|
|
Vector3[] vertices;
|
|
Matrix4x4 matrix;
|
|
|
|
//Generate the mesh and get information about the text and the characters
|
|
m_TextComponent.ForceMeshUpdate();
|
|
|
|
TMP_TextInfo textInfo = m_TextComponent.textInfo;
|
|
int characterCount = textInfo.characterCount;
|
|
|
|
//if the string is empty, no need to waste time
|
|
if (characterCount == 0)
|
|
return;
|
|
|
|
//gets the bounds of the rectangle that contains the text
|
|
float boundsMinX = m_TextComponent.bounds.min.x;
|
|
float boundsMaxX = m_TextComponent.bounds.max.x;
|
|
|
|
//计算总长度
|
|
var width = m_TextComponent.preferredWidth;
|
|
|
|
//for each character
|
|
for (int i = 0; i < characterCount; i++)
|
|
{
|
|
//skip if it is invisible
|
|
if (!textInfo.characterInfo[i].isVisible)
|
|
continue;
|
|
|
|
//Get the index of the mesh used by this character, then the one of the material... and use all this data to get
|
|
//the 4 vertices of the rect that encloses this character. Store them in vertices
|
|
int vertexIndex = textInfo.characterInfo[i].vertexIndex;
|
|
int materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
|
|
vertices = textInfo.meshInfo[materialIndex].vertices;
|
|
|
|
//Compute the baseline mid point for each character. This is the central point of the character.
|
|
//we will use this as the point representing this character for the geometry transformations
|
|
Vector3 charMidBaselinePos = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine);
|
|
|
|
//remove the central point from the vertices point. After this operation, every one of the four vertices
|
|
//will just have as coordinates the offset from the central position. This will come handy when will deal with the rotations
|
|
vertices[vertexIndex + 0] += -charMidBaselinePos;
|
|
vertices[vertexIndex + 1] += -charMidBaselinePos;
|
|
vertices[vertexIndex + 2] += -charMidBaselinePos;
|
|
vertices[vertexIndex + 3] += -charMidBaselinePos;
|
|
|
|
//compute the horizontal position of the character relative to the bounds of the box, in a range [0, 1]
|
|
//where 0 is the left border of the text and 1 is the right border
|
|
float zeroToOnePos = (charMidBaselinePos.x - boundsMinX) / (boundsMaxX - boundsMinX);
|
|
|
|
//get the transformation matrix, that maps the vertices, seen as offset from the central character point, to their final
|
|
//position that follows the curve
|
|
|
|
matrix = ComputeTransformationMatrix(charMidBaselinePos, zeroToOnePos, textInfo, i, width);
|
|
|
|
//apply the transformation, and obtain the final position and orientation of the 4 vertices representing this char
|
|
vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]);
|
|
vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]);
|
|
vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]);
|
|
vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]);
|
|
|
|
vertices[vertexIndex + 0] += charMidBaselinePos;
|
|
vertices[vertexIndex + 1] += charMidBaselinePos;
|
|
vertices[vertexIndex + 2] += charMidBaselinePos;
|
|
vertices[vertexIndex + 3] += charMidBaselinePos;
|
|
}
|
|
|
|
//Upload the mesh with the revised information
|
|
m_TextComponent.UpdateVertexData();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Method executed at every frame that checks if some parameters have been changed
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected abstract bool ParametersHaveChanged();
|
|
|
|
/// <summary>
|
|
/// Computes the transformation matrix that maps the offsets of the vertices of each single character from
|
|
/// the character's center to the final destinations of the vertices so that the text follows a curve
|
|
/// </summary>
|
|
/// <param name="charMidBaselinePosfloat">Position of the central point of the character</param>
|
|
/// <param name="zeroToOnePos">Horizontal position of the character relative to the bounds of the box, in a range [0, 1]</param>
|
|
/// <param name="textInfo">Information on the text that we are showing</param>
|
|
/// <param name="charIdx">Index of the character we have to compute the transformation for</param>
|
|
/// <returns>Transformation matrix to be applied to all vertices of the text</returns>
|
|
protected abstract Matrix4x4 ComputeTransformationMatrix(Vector3 charMidBaselinePos, float zeroToOnePos, TMP_TextInfo textInfo, int charIdx, float totalLength);
|
|
}
|