156 lines
4.7 KiB
C#
156 lines
4.7 KiB
C#
using System.Linq;
|
|
using TMPro;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.Splines;
|
|
|
|
namespace space.chikalin.textdecal
|
|
{
|
|
/// <summary>
|
|
///
|
|
/// Should execute after <c>space.chikalin.textdecal.TextMeshProDecal</c> script
|
|
/// </summary>
|
|
[ExecuteAlways]
|
|
[DisallowMultipleComponent]
|
|
[DefaultExecutionOrder(-90)]
|
|
[AddComponentMenu("Mesh/TextMeshPro - Spline")]
|
|
#if UNITY_2021_2_OR_NEWER
|
|
[Icon("Packages/com.unity.splines/Editor/Resources/Icons/SplineComponent.png")]
|
|
#endif
|
|
[RequireComponent(typeof(SplineContainer), typeof(TMP_Text))]
|
|
public class TextMeshProSpline : MonoBehaviour
|
|
{
|
|
private TMP_Text _text;
|
|
private SplineContainer _spline;
|
|
|
|
private Spline DefaultSpline(float3 start, float3 end)
|
|
{
|
|
var spline = new Spline
|
|
{
|
|
{ start, TangentMode.Linear },
|
|
{ end, TangentMode.Linear }
|
|
};
|
|
return spline;
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
_text = GetComponent<TMP_Text>();
|
|
_spline = GetComponent<SplineContainer>();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
_text.OnPreRenderText += OnPreRenderText;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
_text.OnPreRenderText -= OnPreRenderText;
|
|
_text.ClearMesh();
|
|
_text.mesh.RecalculateBounds();
|
|
_text.ForceMeshUpdate();
|
|
}
|
|
|
|
private void OnPreRenderText(TMP_TextInfo textInfo)
|
|
{
|
|
FitSpline(textInfo);
|
|
}
|
|
|
|
private void FitSpline(TMP_TextInfo textInfo)
|
|
{
|
|
FixSpline();
|
|
|
|
var splineLength = _spline.CalculateLength();
|
|
if (splineLength <= 0) return;
|
|
|
|
for (var i = 0; i < textInfo.characterCount; i++)
|
|
{
|
|
if (!textInfo.characterInfo[i].isVisible)
|
|
continue;
|
|
|
|
var vertexIndex = textInfo.characterInfo[i].vertexIndex;
|
|
var materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
|
|
var vertices = textInfo.meshInfo[materialIndex].vertices;
|
|
var bl = vertices[vertexIndex + 0];
|
|
var tr = vertices[vertexIndex + 2];
|
|
var charCenter = bl + (tr - bl) / 2;
|
|
Evaluate(splineLength, charCenter.x, out var position, out var xAxis, out var yAxis);
|
|
xAxis = transform.InverseTransformDirection(math.normalize(xAxis));
|
|
yAxis = transform.InverseTransformDirection(math.normalize(yAxis));
|
|
position = transform.InverseTransformPoint(position);
|
|
var newCenter = position + yAxis * charCenter.y;
|
|
for (var v = 0; v < 4; v++)
|
|
{
|
|
var d = vertices[vertexIndex + v] - charCenter;
|
|
vertices[vertexIndex + v] = newCenter + xAxis * d.x + yAxis * d.y;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void FixSpline()
|
|
{
|
|
var textRectTransform = _text.rectTransform;
|
|
if (_spline.Spline.Count >= 2) return;
|
|
var rect = textRectTransform.rect;
|
|
var position = textRectTransform.position;
|
|
var start = new float3(rect.xMin, rect.yMin, position.z);
|
|
var end = new float3(rect.xMax, rect.yMax, position.z);
|
|
_spline.Spline = DefaultSpline(start, end);
|
|
}
|
|
|
|
private void Evaluate(float length, float xPos, out float3 position, out float3 xAxis, out float3 yAxis)
|
|
{
|
|
var s = (xPos / length) * transform.localScale.x + .5f; // centered
|
|
_spline.Evaluate(math.clamp(s, 0.01f, .99f), out position, out xAxis, out yAxis);
|
|
}
|
|
|
|
private Quaternion ReflectRotation(Quaternion source, Vector3 normal)
|
|
{
|
|
return Quaternion.LookRotation(Vector3.Reflect(source * Vector3.forward, normal),
|
|
Vector3.Reflect(source * Vector3.up, normal));
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
[ExecuteAlways]
|
|
[ContextMenu("Mirror")]
|
|
public void Mirror()
|
|
{
|
|
var rectTransform = _text.rectTransform;
|
|
rectTransform.GetPositionAndRotation(out var position, out var rotation);
|
|
var max = position + _text.transform.right * rectTransform.rect.width * rectTransform.localScale.x;
|
|
max.x = -max.x;
|
|
var angles = rotation.eulerAngles;
|
|
rotation = Quaternion.Euler(angles.x, 180 - (angles.y - 180), -angles.z);
|
|
rectTransform.SetPositionAndRotation(max, rotation);
|
|
|
|
var spline = _spline.Splines[0];
|
|
var array = spline.Knots.ToArray();
|
|
var lastX = array[^1].Position.x;
|
|
var r = array.Length - 1;
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
var knot = array[i];
|
|
knot.Position.x = -knot.Position.x + lastX;
|
|
spline.SetKnot(r - i, knot);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if UNITY_EDITOR
|
|
private void OnValidate()
|
|
{
|
|
ForceUpdate();
|
|
}
|
|
#endif
|
|
|
|
[ExecuteAlways]
|
|
public void ForceUpdate()
|
|
{
|
|
if (_text != null)
|
|
{
|
|
_text.ForceMeshUpdate();
|
|
}
|
|
}
|
|
}
|
|
} |