/Project/Assets/Scripts/ThirdParty/NGUI/Scripts/UI/UIFilledSprite.cs

https://bitbucket.org/adiq94/villageposition · C# · 466 lines · 360 code · 64 blank · 42 comment · 63 complexity · f605dc271b75743d88dde679032823b3 MD5 · raw file

  1. //----------------------------------------------
  2. // NGUI: Next-Gen UI kit
  3. // Copyright � 2011-2012 Tasharen Entertainment
  4. //----------------------------------------------
  5. using UnityEngine;
  6. using System.Collections.Generic;
  7. /// <summary>
  8. /// Similar to a regular UISprite, but lets you only display a part of it. Great for progress bars, sliders, timers, etc.
  9. /// </summary>
  10. [ExecuteInEditMode]
  11. [AddComponentMenu("NGUI/UI/Sprite (Filled)")]
  12. public class UIFilledSprite : UISprite
  13. {
  14. public enum FillDirection
  15. {
  16. Horizontal,
  17. Vertical,
  18. Radial90,
  19. Radial180,
  20. Radial360,
  21. }
  22. [HideInInspector][SerializeField] FillDirection mFillDirection = FillDirection.Radial360;
  23. [HideInInspector][SerializeField] float mFillAmount = 1.0f;
  24. [HideInInspector][SerializeField] bool mInvert = false;
  25. /// <summary>
  26. /// Direction of the cut procedure.
  27. /// </summary>
  28. public FillDirection fillDirection
  29. {
  30. get
  31. {
  32. return mFillDirection;
  33. }
  34. set
  35. {
  36. if (mFillDirection != value)
  37. {
  38. mFillDirection = value;
  39. mChanged = true;
  40. }
  41. }
  42. }
  43. /// <summary>
  44. /// Amount of the sprite shown. 0-1 range with 0 being nothing shown, and 1 being the full sprite.
  45. /// </summary>
  46. public float fillAmount
  47. {
  48. get
  49. {
  50. return mFillAmount;
  51. }
  52. set
  53. {
  54. float val = Mathf.Clamp01(value);
  55. if (mFillAmount != val)
  56. {
  57. mFillAmount = val;
  58. mChanged = true;
  59. }
  60. }
  61. }
  62. /// <summary>
  63. /// Whether the sprite should be filled in the opposite direction.
  64. /// </summary>
  65. public bool invert
  66. {
  67. get
  68. {
  69. return mInvert;
  70. }
  71. set
  72. {
  73. if (mInvert != value)
  74. {
  75. mInvert = value;
  76. mChanged = true;
  77. }
  78. }
  79. }
  80. /// <summary>
  81. /// Adjust the specified quad, making it be radially filled instead.
  82. /// </summary>
  83. bool AdjustRadial (Vector2[] xy, Vector2[] uv, float fill, bool invert)
  84. {
  85. // Nothing to fill
  86. if (fill < 0.001f) return false;
  87. // Nothing to adjust
  88. if (!invert && fill > 0.999f) return true;
  89. // Convert 0-1 value into 0 to 90 degrees angle in radians
  90. float angle = Mathf.Clamp01(fill);
  91. if (!invert) angle = 1f - angle;
  92. angle *= 90f * Mathf.Deg2Rad;
  93. // Calculate the effective X and Y factors
  94. float fx = Mathf.Sin(angle);
  95. float fy = Mathf.Cos(angle);
  96. // Normalize the result, so it's projected onto the side of the rectangle
  97. if (fx > fy)
  98. {
  99. fy *= 1f / fx;
  100. fx = 1f;
  101. if (!invert)
  102. {
  103. xy[0].y = Mathf.Lerp(xy[2].y, xy[0].y, fy);
  104. xy[3].y = xy[0].y;
  105. uv[0].y = Mathf.Lerp(uv[2].y, uv[0].y, fy);
  106. uv[3].y = uv[0].y;
  107. }
  108. }
  109. else if (fy > fx)
  110. {
  111. fx *= 1f / fy;
  112. fy = 1f;
  113. if (invert)
  114. {
  115. xy[0].x = Mathf.Lerp(xy[2].x, xy[0].x, fx);
  116. xy[1].x = xy[0].x;
  117. uv[0].x = Mathf.Lerp(uv[2].x, uv[0].x, fx);
  118. uv[1].x = uv[0].x;
  119. }
  120. }
  121. else
  122. {
  123. fx = 1f;
  124. fy = 1f;
  125. }
  126. if (invert)
  127. {
  128. xy[1].y = Mathf.Lerp(xy[2].y, xy[0].y, fy);
  129. uv[1].y = Mathf.Lerp(uv[2].y, uv[0].y, fy);
  130. }
  131. else
  132. {
  133. xy[3].x = Mathf.Lerp(xy[2].x, xy[0].x, fx);
  134. uv[3].x = Mathf.Lerp(uv[2].x, uv[0].x, fx);
  135. }
  136. return true;
  137. }
  138. /// <summary>
  139. /// Helper function that copies the contents of the array, rotated by the specified offset.
  140. /// </summary>
  141. void Rotate (Vector2[] v, int offset)
  142. {
  143. for (int i = 0; i < offset; ++i)
  144. {
  145. Vector2 v0 = new Vector2(v[3].x, v[3].y);
  146. v[3].x = v[2].y;
  147. v[3].y = v[2].x;
  148. v[2].x = v[1].y;
  149. v[2].y = v[1].x;
  150. v[1].x = v[0].y;
  151. v[1].y = v[0].x;
  152. v[0].x = v0.y;
  153. v[0].y = v0.x;
  154. }
  155. }
  156. /// <summary>
  157. /// Virtual function called by the UIScreen that fills the buffers.
  158. /// </summary>
  159. #if UNITY_3_5_4
  160. override public void OnFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color> cols)
  161. #else
  162. override public void OnFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
  163. #endif
  164. {
  165. float x0 = 0f;
  166. float y0 = 0f;
  167. float x1 = 1f;
  168. float y1 = -1f;
  169. float u0 = mOuterUV.xMin;
  170. float v0 = mOuterUV.yMin;
  171. float u1 = mOuterUV.xMax;
  172. float v1 = mOuterUV.yMax;
  173. // Horizontal and vertical filled sprites are simple -- just end the sprite prematurely
  174. if (mFillDirection == FillDirection.Horizontal || mFillDirection == FillDirection.Vertical)
  175. {
  176. float du = (u1 - u0) * mFillAmount;
  177. float dv = (v1 - v0) * mFillAmount;
  178. if (fillDirection == FillDirection.Horizontal)
  179. {
  180. if (mInvert)
  181. {
  182. x0 = (1f - mFillAmount);
  183. u0 = u1 - du;
  184. }
  185. else
  186. {
  187. x1 *= mFillAmount;
  188. u1 = u0 + du;
  189. }
  190. }
  191. else if (fillDirection == FillDirection.Vertical)
  192. {
  193. if (mInvert)
  194. {
  195. y1 *= mFillAmount;
  196. v0 = v1 - dv;
  197. }
  198. else
  199. {
  200. y0 = -(1f - mFillAmount);
  201. v1 = v0 + dv;
  202. }
  203. }
  204. }
  205. // Starting quad for the sprite
  206. Vector2[] xy = new Vector2[4];
  207. Vector2[] uv = new Vector2[4];
  208. xy[0] = new Vector2(x1, y0);
  209. xy[1] = new Vector2(x1, y1);
  210. xy[2] = new Vector2(x0, y1);
  211. xy[3] = new Vector2(x0, y0);
  212. uv[0] = new Vector2(u1, v1);
  213. uv[1] = new Vector2(u1, v0);
  214. uv[2] = new Vector2(u0, v0);
  215. uv[3] = new Vector2(u0, v1);
  216. Color colF = color;
  217. colF.a *= mPanel.alpha;
  218. #if UNITY_3_5_4
  219. Color col = atlas.premultipliedAlpha ? NGUITools.ApplyPMA(colF) : colF;
  220. #else
  221. Color32 col = atlas.premultipliedAlpha ? NGUITools.ApplyPMA(colF) : colF;
  222. #endif
  223. if (fillDirection == FillDirection.Radial90)
  224. {
  225. // Adjust the quad radially, and if 'false' is returned (it's not visible), just exit
  226. if (!AdjustRadial(xy, uv, mFillAmount, mInvert)) return;
  227. }
  228. else if (fillDirection == FillDirection.Radial180)
  229. {
  230. // Working in 0-1 coordinates is easier
  231. Vector2[] oxy = new Vector2[4];
  232. Vector2[] ouv = new Vector2[4];
  233. for (int i = 0; i < 2; ++i)
  234. {
  235. oxy[0] = new Vector2(0f, 0f);
  236. oxy[1] = new Vector2(0f, 1f);
  237. oxy[2] = new Vector2(1f, 1f);
  238. oxy[3] = new Vector2(1f, 0f);
  239. ouv[0] = new Vector2(0f, 0f);
  240. ouv[1] = new Vector2(0f, 1f);
  241. ouv[2] = new Vector2(1f, 1f);
  242. ouv[3] = new Vector2(1f, 0f);
  243. // Each half must be rotated 90 degrees clockwise in order for it to fill properly
  244. if (mInvert)
  245. {
  246. if (i > 0)
  247. {
  248. Rotate(oxy, i);
  249. Rotate(ouv, i);
  250. }
  251. }
  252. else if (i < 1)
  253. {
  254. Rotate(oxy, 1 - i);
  255. Rotate(ouv, 1 - i);
  256. }
  257. // Each half must fill in only a part of the space
  258. float x, y;
  259. if (i == 1)
  260. {
  261. x = mInvert ? 0.5f : 1f;
  262. y = mInvert ? 1f : 0.5f;
  263. }
  264. else
  265. {
  266. x = mInvert ? 1f : 0.5f;
  267. y = mInvert ? 0.5f : 1f;
  268. }
  269. oxy[1].y = Mathf.Lerp(x, y, oxy[1].y);
  270. oxy[2].y = Mathf.Lerp(x, y, oxy[2].y);
  271. ouv[1].y = Mathf.Lerp(x, y, ouv[1].y);
  272. ouv[2].y = Mathf.Lerp(x, y, ouv[2].y);
  273. float amount = (mFillAmount) * 2 - i;
  274. bool odd = (i % 2) == 1;
  275. if (AdjustRadial(oxy, ouv, amount, !odd))
  276. {
  277. if (mInvert) odd = !odd;
  278. // Add every other side in reverse order so they don't come out backface-culled due to rotation
  279. if (odd)
  280. {
  281. for (int b = 0; b < 4; ++b)
  282. {
  283. x = Mathf.Lerp(xy[0].x, xy[2].x, oxy[b].x);
  284. y = Mathf.Lerp(xy[0].y, xy[2].y, oxy[b].y);
  285. float u = Mathf.Lerp(uv[0].x, uv[2].x, ouv[b].x);
  286. float v = Mathf.Lerp(uv[0].y, uv[2].y, ouv[b].y);
  287. verts.Add(new Vector3(x, y, 0f));
  288. uvs.Add(new Vector2(u, v));
  289. cols.Add(col);
  290. }
  291. }
  292. else
  293. {
  294. for (int b = 3; b > -1; --b)
  295. {
  296. x = Mathf.Lerp(xy[0].x, xy[2].x, oxy[b].x);
  297. y = Mathf.Lerp(xy[0].y, xy[2].y, oxy[b].y);
  298. float u = Mathf.Lerp(uv[0].x, uv[2].x, ouv[b].x);
  299. float v = Mathf.Lerp(uv[0].y, uv[2].y, ouv[b].y);
  300. verts.Add(new Vector3(x, y, 0f));
  301. uvs.Add(new Vector2(u, v));
  302. cols.Add(col);
  303. }
  304. }
  305. }
  306. }
  307. return;
  308. }
  309. else if (fillDirection == FillDirection.Radial360)
  310. {
  311. float[] matrix = new float[]
  312. {
  313. // x0 y0 x1 y1
  314. 0.5f, 1f, 0f, 0.5f, // quadrant 0
  315. 0.5f, 1f, 0.5f, 1f, // quadrant 1
  316. 0f, 0.5f, 0.5f, 1f, // quadrant 2
  317. 0f, 0.5f, 0f, 0.5f, // quadrant 3
  318. };
  319. Vector2[] oxy = new Vector2[4];
  320. Vector2[] ouv = new Vector2[4];
  321. for (int i = 0; i < 4; ++i)
  322. {
  323. oxy[0] = new Vector2(0f, 0f);
  324. oxy[1] = new Vector2(0f, 1f);
  325. oxy[2] = new Vector2(1f, 1f);
  326. oxy[3] = new Vector2(1f, 0f);
  327. ouv[0] = new Vector2(0f, 0f);
  328. ouv[1] = new Vector2(0f, 1f);
  329. ouv[2] = new Vector2(1f, 1f);
  330. ouv[3] = new Vector2(1f, 0f);
  331. // Each quadrant must be rotated 90 degrees clockwise in order for it to fill properly
  332. if (mInvert)
  333. {
  334. if (i > 0)
  335. {
  336. Rotate(oxy, i);
  337. Rotate(ouv, i);
  338. }
  339. }
  340. else if (i < 3)
  341. {
  342. Rotate(oxy, 3 - i);
  343. Rotate(ouv, 3 - i);
  344. }
  345. // Each quadrant must fill in only a quarter of the space
  346. for (int b = 0; b < 4; ++b)
  347. {
  348. int index = (mInvert) ? (3 - i) * 4 : i * 4;
  349. float fx0 = matrix[index];
  350. float fy0 = matrix[index + 1];
  351. float fx1 = matrix[index + 2];
  352. float fy1 = matrix[index + 3];
  353. oxy[b].x = Mathf.Lerp(fx0, fy0, oxy[b].x);
  354. oxy[b].y = Mathf.Lerp(fx1, fy1, oxy[b].y);
  355. ouv[b].x = Mathf.Lerp(fx0, fy0, ouv[b].x);
  356. ouv[b].y = Mathf.Lerp(fx1, fy1, ouv[b].y);
  357. }
  358. float amount = (mFillAmount) * 4 - i;
  359. bool odd = (i % 2) == 1;
  360. if (AdjustRadial(oxy, ouv, amount, !odd))
  361. {
  362. if (mInvert) odd = !odd;
  363. // Add every other side in reverse order so they don't come out backface-culled due to rotation
  364. if (odd)
  365. {
  366. for (int b = 0; b < 4; ++b)
  367. {
  368. float x = Mathf.Lerp(xy[0].x, xy[2].x, oxy[b].x);
  369. float y = Mathf.Lerp(xy[0].y, xy[2].y, oxy[b].y);
  370. float u = Mathf.Lerp(uv[0].x, uv[2].x, ouv[b].x);
  371. float v = Mathf.Lerp(uv[0].y, uv[2].y, ouv[b].y);
  372. verts.Add(new Vector3(x, y, 0f));
  373. uvs.Add(new Vector2(u, v));
  374. cols.Add(col);
  375. }
  376. }
  377. else
  378. {
  379. for (int b = 3; b > -1; --b)
  380. {
  381. float x = Mathf.Lerp(xy[0].x, xy[2].x, oxy[b].x);
  382. float y = Mathf.Lerp(xy[0].y, xy[2].y, oxy[b].y);
  383. float u = Mathf.Lerp(uv[0].x, uv[2].x, ouv[b].x);
  384. float v = Mathf.Lerp(uv[0].y, uv[2].y, ouv[b].y);
  385. verts.Add(new Vector3(x, y, 0f));
  386. uvs.Add(new Vector2(u, v));
  387. cols.Add(col);
  388. }
  389. }
  390. }
  391. }
  392. return;
  393. }
  394. // Fill the buffer with the quad for the sprite
  395. for (int i = 0; i < 4; ++i)
  396. {
  397. verts.Add(xy[i]);
  398. uvs.Add(uv[i]);
  399. cols.Add(col);
  400. }
  401. }
  402. }