CurvedUITMP.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using System.Collections.Generic;
  4. #if CURVEDUI_TMP || TMP_PRESENT
  5. using TMPro;
  6. #endif
  7. //To use this class you have to add CURVEDUI_TMP to your define symbols. You can do it in project settings.
  8. //To learn how to do it visit http://docs.unity3d.com/Manual/PlatformDependentCompilation.html and search for "Platform Custom Defines"
  9. namespace CurvedUI
  10. {
  11. [ExecuteInEditMode]
  12. public class CurvedUITMP : MonoBehaviour
  13. {
  14. #if CURVEDUI_TMP || TMP_PRESENT
  15. //internal
  16. CurvedUIVertexEffect crvdVE;
  17. TextMeshProUGUI tmpText;
  18. CurvedUISettings mySettings;
  19. List<UIVertex> m_UIVerts = new List<UIVertex>();
  20. UIVertex m_tempVertex;
  21. CurvedUITMPSubmesh m_tempSubMsh;
  22. Vector2 savedSize;
  23. Vector3 savedUp;
  24. Vector3 savedPos;
  25. Vector3 savedLocalScale;
  26. Vector3 savedGlobalScale;
  27. List<CurvedUITMPSubmesh> subMeshes = new List<CurvedUITMPSubmesh>();
  28. //flags
  29. public bool Dirty = false; // set this to true to force mesh update.
  30. bool curvingRequired = false;
  31. bool tesselationRequired = false;
  32. bool quitting = false;
  33. //mesh data
  34. private Vector3[] vertices;
  35. //These are commented here and throught the script,
  36. //cause CurvedUI operates only on vertex positions,
  37. //but left here for future-proofing against some TMP features.
  38. //private Color32[] colors32;
  39. //private Vector2[] uv;
  40. //private Vector2[] uv2;
  41. //private Vector2[] uv3;
  42. //private Vector2[] uv4;
  43. //private Vector3[] normals;
  44. //private Vector4[] tangents;
  45. //private int[] indices;
  46. #region LIFECYCLE
  47. void Start()
  48. {
  49. if (mySettings == null)
  50. mySettings = GetComponentInParent<CurvedUISettings>();
  51. }
  52. void OnEnable()
  53. {
  54. FindTMP();
  55. if (tmpText)
  56. {
  57. tmpText.RegisterDirtyMaterialCallback(TesselationRequiredCallback);
  58. TMPro_EventManager.TEXT_CHANGED_EVENT.Add(TMPTextChangedCallback);
  59. tmpText.SetText(tmpText.text);
  60. }
  61. #if UNITY_EDITOR
  62. if (!Application.isPlaying)
  63. UnityEditor.EditorApplication.update += LateUpdate;
  64. #endif
  65. }
  66. void OnDisable()
  67. {
  68. #if UNITY_EDITOR
  69. if (!Application.isPlaying)
  70. UnityEditor.EditorApplication.update -= LateUpdate;
  71. #endif
  72. if (tmpText)
  73. {
  74. tmpText.UnregisterDirtyMaterialCallback(TesselationRequiredCallback);
  75. TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(TMPTextChangedCallback);
  76. }
  77. }
  78. void OnDestroy()
  79. {
  80. quitting = true;
  81. }
  82. void LateUpdate()
  83. {
  84. //if we're missing stuff, find it
  85. if (!tmpText) FindTMP();
  86. if (mySettings == null) return;
  87. //Edit Mesh on TextMeshPro component
  88. if (tmpText && !quitting)
  89. {
  90. if (ShouldTesselate())
  91. tesselationRequired = true;
  92. if (Dirty || tesselationRequired || (curvingRequired && !Application.isPlaying))
  93. {
  94. if (mySettings == null)
  95. {
  96. enabled = false;
  97. return;
  98. }
  99. //Get the flat vertices from TMP object.
  100. //store a copy of flat UIVertices for later so we dont have to retrieve the Mesh every framee.
  101. tmpText.renderMode = TMPro.TextRenderFlags.Render;
  102. tmpText.ForceMeshUpdate(true);
  103. CreateUIVertexList(tmpText.mesh);
  104. //Tesselate and Curve the flat UIVertices stored in Vertex Helper
  105. crvdVE.ModifyTMPMesh(ref m_UIVerts);
  106. //fill curved vertices back to TMP mesh
  107. FillMeshWithUIVertexList(tmpText.mesh, m_UIVerts);
  108. //cleanup
  109. tmpText.renderMode = TMPro.TextRenderFlags.DontRender;
  110. //save current data
  111. savedLocalScale = mySettings.transform.localScale;
  112. savedGlobalScale = mySettings.transform.lossyScale;
  113. savedSize = (transform as RectTransform).rect.size;
  114. savedUp = mySettings.transform.worldToLocalMatrix.MultiplyVector(transform.up);
  115. savedPos = mySettings.transform.worldToLocalMatrix.MultiplyPoint3x4(transform.position);
  116. //reset flags
  117. tesselationRequired = false;
  118. curvingRequired = false;
  119. Dirty = false;
  120. //prompt submeshes to update
  121. FindSubmeshes();
  122. foreach (CurvedUITMPSubmesh mesh in subMeshes)
  123. mesh.UpdateSubmesh(true, false);
  124. }
  125. //Upload mesh to TMP Object's renderer
  126. tmpText.canvasRenderer.SetMesh(tmpText.mesh);
  127. }
  128. }
  129. #endregion
  130. #region UIVERTEX MANAGEMENT
  131. void CreateUIVertexList(Mesh mesh)
  132. {
  133. //trim if too long list
  134. if (mesh.vertexCount < m_UIVerts.Count)
  135. m_UIVerts.RemoveRange(mesh.vertexCount, m_UIVerts.Count - mesh.vertexCount);
  136. //extract mesh data
  137. vertices = mesh.vertices;
  138. //colors32 = mesh.colors32;
  139. //uv = mesh.uv;
  140. //uv2 = mesh.uv2;
  141. //uv3 = mesh.uv3;
  142. //uv4 = mesh.uv4;
  143. //normals = mesh.normals;
  144. //tangents = mesh.tangents;
  145. for (int i = 0; i < mesh.vertexCount; i++)
  146. {
  147. //add if list too short
  148. if (m_UIVerts.Count <= i)
  149. {
  150. m_tempVertex = new UIVertex();
  151. GetUIVertexFromMesh(ref m_tempVertex, i);
  152. m_UIVerts.Add(m_tempVertex);
  153. }
  154. else //modify
  155. {
  156. m_tempVertex = m_UIVerts[i];
  157. GetUIVertexFromMesh(ref m_tempVertex, i);
  158. m_UIVerts[i] = m_tempVertex;
  159. }
  160. }
  161. //indices = mesh.GetIndices(0);
  162. }
  163. void GetUIVertexFromMesh(ref UIVertex vert, int i)
  164. {
  165. vert.position = vertices[i];
  166. //vert.color = colors32[i];
  167. //vert.uv0 = uv[i];
  168. //vert.uv1 = uv2.Length > i ? uv2[i] : Vector2.zero;
  169. //vert.uv2 = uv3.Length > i ? uv3[i] : Vector2.zero;
  170. //vert.uv3 = uv4.Length > i ? uv4[i] : Vector2.zero;
  171. //vert.normal = normals[i];
  172. //vert.tangent = tangents[i];
  173. }
  174. void FillMeshWithUIVertexList(Mesh mesh, List<UIVertex> list)
  175. {
  176. if (list.Count >= 65536)
  177. {
  178. Debug.LogError("CURVEDUI: Unity UI Mesh can not have more than 65536 vertices. Remove some UI elements or lower quality.");
  179. return;
  180. }
  181. for (int i = 0; i < list.Count; i++)
  182. {
  183. vertices[i] = list[i].position;
  184. //colors32[i] = list[i].color;
  185. //uv[i] = list[i].uv0;
  186. //if (uv2.Length < i) uv2[i] = list[i].uv1;
  187. ////if (uv3.Length < i) uv3[i] = list[i].uv2;
  188. ////if (uv4.Length < i) uv4[i] = list[i].uv3;
  189. //normals[i] = list[i].normal;
  190. //tangents[i] = list[i].tangent;
  191. }
  192. //Fill mesh with data
  193. mesh.vertices = vertices;
  194. //mesh.colors32 = colors32;
  195. //mesh.uv = uv;
  196. //mesh.uv2 = uv2;
  197. ////mesh.uv3 = uv3;
  198. ////mesh.uv4 = uv4;
  199. //mesh.normals = normals;
  200. //mesh.tangents = tangents;
  201. //mesh.SetTriangles(indices, 0);
  202. mesh.RecalculateBounds();
  203. }
  204. #endregion
  205. #region PRIVATE
  206. void FindTMP()
  207. {
  208. if (this.GetComponent<TextMeshProUGUI>() != null)
  209. {
  210. tmpText = this.gameObject.GetComponent<TextMeshProUGUI>();
  211. crvdVE = this.gameObject.GetComponent<CurvedUIVertexEffect>();
  212. mySettings = GetComponentInParent<CurvedUISettings>();
  213. transform.hasChanged = false;
  214. FindSubmeshes();
  215. }
  216. }
  217. void FindSubmeshes()
  218. {
  219. foreach (TMP_SubMeshUI sub in GetComponentsInChildren<TMP_SubMeshUI>())
  220. {
  221. m_tempSubMsh = sub.gameObject.AddComponentIfMissing<CurvedUITMPSubmesh>();
  222. if (!subMeshes.Contains(m_tempSubMsh))
  223. subMeshes.Add(m_tempSubMsh);
  224. }
  225. }
  226. bool ShouldTesselate()
  227. {
  228. if (savedSize != (transform as RectTransform).rect.size)
  229. {
  230. //Debug.Log("size changed");
  231. return true;
  232. }
  233. else if (savedLocalScale != mySettings.transform.localScale)
  234. {
  235. //Debug.Log("local scale changed");
  236. return true;
  237. }
  238. else if (savedGlobalScale != mySettings.transform.lossyScale)
  239. {
  240. //Debug.Log("global scale changed");
  241. return true;
  242. }
  243. else if (!savedUp.AlmostEqual(mySettings.transform.worldToLocalMatrix.MultiplyVector(transform.up)))
  244. {
  245. // Debug.Log("up changed");
  246. return true;
  247. }
  248. Vector3 testedPos = mySettings.transform.worldToLocalMatrix.MultiplyPoint3x4(transform.position);
  249. if (!savedPos.AlmostEqual(testedPos))
  250. {
  251. //we dont have to curve vertices if we only moved the object vertically in a cylinder.
  252. if (mySettings.Shape != CurvedUISettings.CurvedUIShape.CYLINDER || Mathf.Pow(testedPos.x - savedPos.x, 2) > 0.00001 || Mathf.Pow(testedPos.z - savedPos.z, 2) > 0.00001)
  253. {
  254. //Debug.Log("pos changed");
  255. return true;
  256. }
  257. }
  258. return false;
  259. }
  260. #endregion
  261. #region EVENTS AND CALLBACKS
  262. void TMPTextChangedCallback(object obj)
  263. {
  264. if (obj != (object)tmpText) return;
  265. tesselationRequired = true;
  266. //Debug.Log("tmp prop changed on "+this.gameObject.name, this.gameObject);
  267. }
  268. void TesselationRequiredCallback()
  269. {
  270. tesselationRequired = true;
  271. curvingRequired = true;
  272. }
  273. #endregion
  274. #endif
  275. }
  276. }