UISquircle.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /// Credit Soprachev Andrei
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEditor;
  5. namespace UnityEngine.UI.Extensions
  6. {
  7. [AddComponentMenu("UI/Extensions/Primitives/Squircle")]
  8. public class UISquircle : UIPrimitiveBase
  9. {
  10. const float C = 1.0f;
  11. public enum Type
  12. {
  13. Classic,
  14. Scaled
  15. }
  16. [Space]
  17. public Type squircleType = Type.Scaled;
  18. [Range(1, 40)]
  19. public float n = 4;
  20. [Min(0.1f)]
  21. public float delta = 5f;
  22. public float quality = 0.1f;
  23. [Min(0)]
  24. public float radius = 1000;
  25. private float a, b;
  26. private List<Vector2> vert = new List<Vector2>();
  27. private float SquircleFunc(float t, bool xByY)
  28. {
  29. if (xByY)
  30. return (float)System.Math.Pow(C - System.Math.Pow(t / a, n), 1f / n) * b;
  31. return (float)System.Math.Pow(C - System.Math.Pow(t / b, n), 1f / n) * a;
  32. }
  33. protected override void OnPopulateMesh(VertexHelper vh)
  34. {
  35. float dx = 0;
  36. float dy = 0;
  37. float width = rectTransform.rect.width / 2;
  38. float height = rectTransform.rect.height / 2;
  39. if (squircleType == Type.Classic)
  40. {
  41. a = width;
  42. b = height;
  43. }
  44. else
  45. {
  46. a = Mathf.Min(width, height, radius);
  47. b = a;
  48. dx = width - a;
  49. dy = height - a;
  50. }
  51. float x = 0;
  52. float y = 1;
  53. vert.Clear();
  54. vert.Add(new Vector2(0, height));
  55. while (x < y)
  56. {
  57. y = SquircleFunc(x, true);
  58. vert.Add(new Vector2(dx + x, dy + y));
  59. x += delta;
  60. }
  61. if (float.IsNaN(vert.Last().y))
  62. {
  63. vert.RemoveAt(vert.Count - 1);
  64. }
  65. while (y > 0)
  66. {
  67. x = SquircleFunc(y, false);
  68. vert.Add(new Vector2(dx + x, dy + y));
  69. y -= delta;
  70. }
  71. vert.Add(new Vector2(width, 0));
  72. for (int i = 1; i < vert.Count - 1; i++)
  73. {
  74. if (vert[i].x < vert[i].y)
  75. {
  76. if (vert[i - 1].y - vert[i].y < quality)
  77. {
  78. vert.RemoveAt(i);
  79. i -= 1;
  80. }
  81. }
  82. else
  83. {
  84. if (vert[i].x - vert[i - 1].x < quality)
  85. {
  86. vert.RemoveAt(i);
  87. i -= 1;
  88. }
  89. }
  90. }
  91. vert.AddRange(vert.AsEnumerable().Reverse().Select(t => new Vector2(t.x, -t.y)));
  92. vert.AddRange(vert.AsEnumerable().Reverse().Select(t => new Vector2(-t.x, t.y)));
  93. vh.Clear();
  94. for (int i = 0; i < vert.Count - 1; i++)
  95. {
  96. vh.AddVert(vert[i], color, Vector2.zero);
  97. vh.AddVert(vert[i + 1], color, Vector2.zero);
  98. vh.AddVert(Vector2.zero, color, Vector2.zero);
  99. vh.AddTriangle(i * 3, i * 3 + 1, i * 3 + 2);
  100. }
  101. }
  102. #if UNITY_EDITOR
  103. [CustomEditor(typeof(UISquircle))]
  104. public class UISquircleEditor : Editor
  105. {
  106. public override void OnInspectorGUI()
  107. {
  108. DrawDefaultInspector();
  109. UISquircle script = (UISquircle)target;
  110. GUILayout.Label("Vertex count: " + script.vert.Count().ToString());
  111. }
  112. }
  113. #endif
  114. }
  115. }