UIShadow.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Serialization;
  5. using UnityEngine.UI;
  6. #if UNITY_EDITOR
  7. using System.IO;
  8. using System.Linq;
  9. using UnityEditor;
  10. #endif
  11. namespace Coffee.UIEffects
  12. {
  13. /// <summary>
  14. /// UIEffect.
  15. /// </summary>
  16. [RequireComponent(typeof(Graphic))]
  17. [AddComponentMenu("UI/UIEffects/UIShadow", 100)]
  18. public class UIShadow : BaseMeshEffect, IParameterTexture
  19. {
  20. static readonly List<UIShadow> tmpShadows = new List<UIShadow>();
  21. static readonly List<UIVertex> s_Verts = new List<UIVertex>(4096);
  22. int _graphicVertexCount;
  23. UIEffect _uiEffect;
  24. [Tooltip("How far is the blurring shadow from the graphic.")]
  25. [FormerlySerializedAs("m_Blur")]
  26. [SerializeField]
  27. [Range(0, 1)]
  28. float m_BlurFactor = 1;
  29. [Tooltip("Shadow effect style.")] [SerializeField]
  30. ShadowStyle m_Style = ShadowStyle.Shadow;
  31. [SerializeField] private Color m_EffectColor = new Color(0f, 0f, 0f, 0.5f);
  32. [SerializeField] private Vector2 m_EffectDistance = new Vector2(1f, -1f);
  33. [SerializeField] private bool m_UseGraphicAlpha = true;
  34. private const float kMaxEffectDistance = 600f;
  35. public Color effectColor
  36. {
  37. get { return m_EffectColor; }
  38. set
  39. {
  40. if (m_EffectColor == value) return;
  41. m_EffectColor = value;
  42. SetVerticesDirty();
  43. }
  44. }
  45. public Vector2 effectDistance
  46. {
  47. get { return m_EffectDistance; }
  48. set
  49. {
  50. if (value.x > kMaxEffectDistance)
  51. value.x = kMaxEffectDistance;
  52. if (value.x < -kMaxEffectDistance)
  53. value.x = -kMaxEffectDistance;
  54. if (value.y > kMaxEffectDistance)
  55. value.y = kMaxEffectDistance;
  56. if (value.y < -kMaxEffectDistance)
  57. value.y = -kMaxEffectDistance;
  58. if (m_EffectDistance == value) return;
  59. m_EffectDistance = value;
  60. SetEffectParamsDirty();
  61. }
  62. }
  63. public bool useGraphicAlpha
  64. {
  65. get { return m_UseGraphicAlpha; }
  66. set
  67. {
  68. if (m_UseGraphicAlpha == value) return;
  69. m_UseGraphicAlpha = value;
  70. SetEffectParamsDirty();
  71. }
  72. }
  73. /// <summary>
  74. /// How far is the blurring shadow from the graphic.
  75. /// </summary>
  76. public float blurFactor
  77. {
  78. get { return m_BlurFactor; }
  79. set
  80. {
  81. value = Mathf.Clamp(value, 0, 2);
  82. if (Mathf.Approximately(m_BlurFactor, value)) return;
  83. m_BlurFactor = value;
  84. SetEffectParamsDirty();
  85. }
  86. }
  87. /// <summary>
  88. /// Shadow effect style.
  89. /// </summary>
  90. public ShadowStyle style
  91. {
  92. get { return m_Style; }
  93. set
  94. {
  95. if (m_Style == value) return;
  96. m_Style = value;
  97. SetEffectParamsDirty();
  98. }
  99. }
  100. /// <summary>
  101. /// Gets or sets the parameter index.
  102. /// </summary>
  103. public int parameterIndex { get; set; }
  104. /// <summary>
  105. /// Gets the parameter texture.
  106. /// </summary>
  107. public ParameterTexture paramTex { get; private set; }
  108. protected override void OnEnable()
  109. {
  110. base.OnEnable();
  111. _uiEffect = GetComponent<UIEffect>();
  112. if (!_uiEffect) return;
  113. paramTex = _uiEffect.paramTex;
  114. paramTex.Register(this);
  115. }
  116. protected override void OnDisable()
  117. {
  118. base.OnDisable();
  119. _uiEffect = null;
  120. if (paramTex == null) return;
  121. paramTex.Unregister(this);
  122. paramTex = null;
  123. }
  124. // #if UNITY_EDITOR
  125. // protected override void OnValidate()
  126. // {
  127. // effectDistance = m_EffectDistance;
  128. // base.OnValidate();
  129. // }
  130. // #endif
  131. // #if TMP_PRESENT
  132. // protected void OnCullStateChanged (bool state)
  133. // {
  134. // SetVerticesDirty ();
  135. // }
  136. //
  137. // Vector2 res;
  138. // protected override void LateUpdate ()
  139. // {
  140. // if (res.x != Screen.width || res.y != Screen.height)
  141. // {
  142. // res.x = Screen.width;
  143. // res.y = Screen.height;
  144. // SetVerticesDirty ();
  145. // }
  146. // if (textMeshPro && transform.hasChanged)
  147. // {
  148. // transform.hasChanged = false;
  149. // }
  150. // base.LateUpdate ();
  151. // }
  152. // #endif
  153. /// <summary>
  154. /// Modifies the mesh.
  155. /// </summary>
  156. public override void ModifyMesh(VertexHelper vh, Graphic graphic)
  157. {
  158. if (!isActiveAndEnabled || vh.currentVertCount <= 0 || m_Style == ShadowStyle.None)
  159. {
  160. return;
  161. }
  162. vh.GetUIVertexStream(s_Verts);
  163. GetComponents<UIShadow>(tmpShadows);
  164. foreach (var s in tmpShadows)
  165. {
  166. if (!s.isActiveAndEnabled) continue;
  167. if (s == this)
  168. {
  169. foreach (var s2 in tmpShadows)
  170. {
  171. s2._graphicVertexCount = s_Verts.Count;
  172. }
  173. }
  174. break;
  175. }
  176. tmpShadows.Clear();
  177. //================================
  178. // Append shadow vertices.
  179. //================================
  180. {
  181. _uiEffect = _uiEffect ? _uiEffect : GetComponent<UIEffect>();
  182. var start = s_Verts.Count - _graphicVertexCount;
  183. var end = s_Verts.Count;
  184. if (paramTex != null && _uiEffect && _uiEffect.isActiveAndEnabled)
  185. {
  186. paramTex.SetData(this, 0, _uiEffect.effectFactor); // param.x : effect factor
  187. paramTex.SetData(this, 1, 255); // param.y : color factor
  188. paramTex.SetData(this, 2, m_BlurFactor); // param.z : blur factor
  189. }
  190. ApplyShadow(s_Verts, effectColor, ref start, ref end, effectDistance, style, useGraphicAlpha);
  191. }
  192. vh.Clear();
  193. vh.AddUIVertexTriangleStream(s_Verts);
  194. s_Verts.Clear();
  195. }
  196. /// <summary>
  197. /// Append shadow vertices.
  198. /// * It is similar to Shadow component implementation.
  199. /// </summary>
  200. private void ApplyShadow(List<UIVertex> verts, Color color, ref int start, ref int end, Vector2 distance,
  201. ShadowStyle style, bool alpha)
  202. {
  203. if (style == ShadowStyle.None || color.a <= 0)
  204. return;
  205. var x = distance.x;
  206. var y = distance.y;
  207. // Append Shadow.
  208. ApplyShadowZeroAlloc(verts, color, ref start, ref end, x, y, alpha);
  209. switch (style)
  210. {
  211. // Append Shadow3.
  212. case ShadowStyle.Shadow3:
  213. ApplyShadowZeroAlloc(verts, color, ref start, ref end, x, 0, alpha);
  214. ApplyShadowZeroAlloc(verts, color, ref start, ref end, 0, y, alpha);
  215. break;
  216. // Append Outline.
  217. case ShadowStyle.Outline:
  218. ApplyShadowZeroAlloc(verts, color, ref start, ref end, x, -y, alpha);
  219. ApplyShadowZeroAlloc(verts, color, ref start, ref end, -x, y, alpha);
  220. ApplyShadowZeroAlloc(verts, color, ref start, ref end, -x, -y, alpha);
  221. break;
  222. // Append Outline8.
  223. case ShadowStyle.Outline8:
  224. ApplyShadowZeroAlloc(verts, color, ref start, ref end, x, -y, alpha);
  225. ApplyShadowZeroAlloc(verts, color, ref start, ref end, -x, y, alpha);
  226. ApplyShadowZeroAlloc(verts, color, ref start, ref end, -x, -y, alpha);
  227. ApplyShadowZeroAlloc(verts, color, ref start, ref end, -x, 0, alpha);
  228. ApplyShadowZeroAlloc(verts, color, ref start, ref end, 0, -y, alpha);
  229. ApplyShadowZeroAlloc(verts, color, ref start, ref end, x, 0, alpha);
  230. ApplyShadowZeroAlloc(verts, color, ref start, ref end, 0, y, alpha);
  231. break;
  232. }
  233. }
  234. /// <summary>
  235. /// Append shadow vertices.
  236. /// * It is similar to Shadow component implementation.
  237. /// </summary>
  238. private void ApplyShadowZeroAlloc(List<UIVertex> verts, Color color, ref int start, ref int end, float x,
  239. float y, bool alpha)
  240. {
  241. // Check list capacity.
  242. var count = end - start;
  243. var neededCapacity = verts.Count + count;
  244. if (verts.Capacity < neededCapacity)
  245. verts.Capacity *= 2;
  246. var normalizedIndex = paramTex != null && _uiEffect && _uiEffect.isActiveAndEnabled
  247. ? paramTex.GetNormalizedIndex(this)
  248. : -1;
  249. // Add
  250. var vt = default(UIVertex);
  251. for (var i = 0; i < count; i++)
  252. {
  253. verts.Add(vt);
  254. }
  255. // Move
  256. for (var i = verts.Count - 1; count <= i; i--)
  257. {
  258. verts[i] = verts[i - count];
  259. }
  260. // Append shadow vertices to the front of list.
  261. // * The original vertex is pushed backward.
  262. for (var i = 0; i < count; ++i)
  263. {
  264. vt = verts[i + start + count];
  265. var v = vt.position;
  266. vt.position.Set(v.x + x, v.y + y, v.z);
  267. var vertColor = effectColor;
  268. vertColor.a = alpha ? color.a * vt.color.a / 255 : color.a;
  269. vt.color = vertColor;
  270. // Set UIEffect parameters
  271. if (0 <= normalizedIndex)
  272. {
  273. vt.uv0 = new Vector2(
  274. vt.uv0.x,
  275. normalizedIndex
  276. );
  277. }
  278. verts[i] = vt;
  279. }
  280. // Update next shadow offset.
  281. start = end;
  282. end = verts.Count;
  283. }
  284. /// <summary>
  285. /// Mark the UIEffect as dirty.
  286. /// </summary>
  287. // void _SetDirty()
  288. // {
  289. // if (graphic)
  290. // graphic.SetVerticesDirty();
  291. // }
  292. // #if UNITY_EDITOR
  293. // public void OnBeforeSerialize()
  294. // {
  295. // }
  296. //
  297. // public void OnAfterDeserialize()
  298. // {
  299. // EditorApplication.delayCall += UpgradeIfNeeded;
  300. // }
  301. //
  302. //
  303. // #pragma warning disable 0612
  304. // void UpgradeIfNeeded()
  305. // {
  306. // if (0 < m_AdditionalShadows.Count)
  307. // {
  308. // foreach (var s in m_AdditionalShadows)
  309. // {
  310. // if (s.style == ShadowStyle.None)
  311. // {
  312. // continue;
  313. // }
  314. //
  315. // var shadow = gameObject.AddComponent<UIShadow>();
  316. // shadow.style = s.style;
  317. // shadow.effectDistance = s.effectDistance;
  318. // shadow.effectColor = s.effectColor;
  319. // shadow.useGraphicAlpha = s.useGraphicAlpha;
  320. // shadow.blurFactor = s.blur;
  321. // }
  322. //
  323. // m_AdditionalShadows = null;
  324. // }
  325. // }
  326. // #pragma warning restore 0612
  327. // #endif
  328. }
  329. }