A game about forced loneliness, made by TACStudios
at master 11 kB view raw
1using System; 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5 6namespace UnityEditor.U2D.Common.Path 7{ 8 internal static class EditablePathExtensions 9 { 10 public static Polygon ToPolygon(this IEditablePath path) 11 { 12 var polygon = new Polygon() 13 { 14 isOpenEnded = path.isOpenEnded, 15 points = new Vector3[path.pointCount] 16 }; 17 18 for (var i = 0; i < path.pointCount; ++i) 19 polygon.points[i] = path.GetPoint(i).position; 20 21 return polygon; 22 } 23 24 public static Spline ToSpline(this IEditablePath path) 25 { 26 var count = path.pointCount * 3; 27 28 if (path.isOpenEnded) 29 count -= 2; 30 31 var spline = new Spline() 32 { 33 isOpenEnded = path.isOpenEnded, 34 points = new Vector3[count] 35 }; 36 37 for (var i = 0; i < path.pointCount; ++i) 38 { 39 var point = path.GetPoint(i); 40 41 spline.points[i*3] = point.position; 42 43 if (i * 3 + 1 < count) 44 { 45 var nextIndex = EditablePathUtility.Mod(i+1, path.pointCount); 46 47 spline.points[i*3 + 1] = path.CalculateRightTangent(i); 48 spline.points[i*3 + 2] = path.CalculateLeftTangent(nextIndex); 49 } 50 } 51 52 return spline; 53 } 54 55 public static Vector3 CalculateLocalLeftTangent(this IEditablePath path, int index) 56 { 57 return path.CalculateLeftTangent(index) - path.GetPoint(index).position; 58 } 59 60 public static Vector3 CalculateLeftTangent(this IEditablePath path, int index) 61 { 62 var point = path.GetPoint(index); 63 var isTangentLinear = point.localLeftTangent == Vector3.zero; 64 var isEndpoint = path.isOpenEnded && index == 0; 65 var tangent = point.leftTangent; 66 67 if (isEndpoint) 68 return point.position; 69 70 if (isTangentLinear) 71 { 72 var prevPoint = path.GetPrevPoint(index); 73 var v = prevPoint.position - point.position; 74 tangent = point.position + v.normalized * (v.magnitude / 3f); 75 } 76 77 return tangent; 78 } 79 80 public static Vector3 CalculateLocalRightTangent(this IEditablePath path, int index) 81 { 82 return path.CalculateRightTangent(index) - path.GetPoint(index).position; 83 } 84 85 public static Vector3 CalculateRightTangent(this IEditablePath path, int index) 86 { 87 var point = path.GetPoint(index); 88 var isTangentLinear = point.localRightTangent == Vector3.zero; 89 var isEndpoint = path.isOpenEnded && index == path.pointCount - 1; 90 var tangent = point.rightTangent; 91 92 if (isEndpoint) 93 return point.position; 94 95 if (isTangentLinear) 96 { 97 var nextPoint = path.GetNextPoint(index); 98 var v = nextPoint.position - point.position; 99 tangent = point.position + v.normalized * (v.magnitude / 3f); 100 } 101 102 return tangent; 103 } 104 105 public static ControlPoint GetPrevPoint(this IEditablePath path, int index) 106 { 107 return path.GetPoint(EditablePathUtility.Mod(index - 1, path.pointCount)); 108 } 109 110 public static ControlPoint GetNextPoint(this IEditablePath path, int index) 111 { 112 return path.GetPoint(EditablePathUtility.Mod(index + 1, path.pointCount)); 113 } 114 115 public static void UpdateTangentMode(this IEditablePath path, int index) 116 { 117 var localToWorldMatrix = path.localToWorldMatrix; 118 path.localToWorldMatrix = Matrix4x4.identity; 119 120 var controlPoint = path.GetPoint(index); 121 var isLeftTangentLinear = controlPoint.localLeftTangent == Vector3.zero; 122 var isRightTangentLinear = controlPoint.localRightTangent == Vector3.zero; 123 124 if (isLeftTangentLinear && isRightTangentLinear) 125 controlPoint.tangentMode = TangentMode.Linear; 126 else if (isLeftTangentLinear || isRightTangentLinear) 127 controlPoint.tangentMode = TangentMode.Broken; 128 else if (controlPoint.tangentMode != TangentMode.Continuous) 129 controlPoint.tangentMode = TangentMode.Broken; 130 131 controlPoint.StoreTangents(); 132 path.SetPoint(index, controlPoint); 133 path.localToWorldMatrix = localToWorldMatrix; 134 } 135 136 public static void UpdateTangentsFromMode(this IEditablePath path) 137 { 138 const float kEpsilon = 0.001f; 139 140 var localToWorldMatrix = path.localToWorldMatrix; 141 path.localToWorldMatrix = Matrix4x4.identity; 142 143 for (var i = 0; i < path.pointCount; ++i) 144 { 145 var controlPoint = path.GetPoint(i); 146 147 if (controlPoint.tangentMode == TangentMode.Linear) 148 { 149 controlPoint.localLeftTangent = Vector3.zero; 150 controlPoint.localRightTangent = Vector3.zero; 151 } 152 else if (controlPoint.tangentMode == TangentMode.Broken) 153 { 154 var isLeftEndpoint = path.isOpenEnded && i == 0; 155 var prevPoint = path.GetPrevPoint(i); 156 var nextPoint = path.GetNextPoint(i); 157 158 var liniarLeftPosition = (prevPoint.position - controlPoint.position) / 3f; 159 var isLeftTangentLinear = isLeftEndpoint || (controlPoint.localLeftTangent - liniarLeftPosition).sqrMagnitude < kEpsilon; 160 161 if (isLeftTangentLinear) 162 controlPoint.localLeftTangent = Vector3.zero; 163 164 var isRightEndpoint = path.isOpenEnded && i == path.pointCount-1; 165 var liniarRightPosition = (nextPoint.position - controlPoint.position) / 3f; 166 var isRightTangentLinear = isRightEndpoint || (controlPoint.localRightTangent - liniarRightPosition).sqrMagnitude < kEpsilon; 167 168 if (isRightTangentLinear) 169 controlPoint.localRightTangent = Vector3.zero; 170 171 if (isLeftTangentLinear && isRightTangentLinear) 172 controlPoint.tangentMode = TangentMode.Linear; 173 } 174 else if (controlPoint.tangentMode == TangentMode.Continuous) 175 { 176 //TODO: ensure tangent continuity 177 } 178 179 controlPoint.StoreTangents(); 180 path.SetPoint(i, controlPoint); 181 } 182 183 path.localToWorldMatrix = localToWorldMatrix; 184 } 185 186 public static void SetTangentMode(this IEditablePath path, int index, TangentMode tangentMode) 187 { 188 var localToWorldMatrix = path.localToWorldMatrix; 189 path.localToWorldMatrix = Matrix4x4.identity; 190 191 var controlPoint = path.GetPoint(index); 192 var isEndpoint = path.isOpenEnded && (index == 0 || index == path.pointCount - 1); 193 var oldTangentMode = controlPoint.tangentMode; 194 195 controlPoint.tangentMode = tangentMode; 196 controlPoint.RestoreTangents(); 197 198 if (tangentMode == TangentMode.Linear) 199 { 200 controlPoint.localLeftTangent = Vector3.zero; 201 controlPoint.localRightTangent = Vector3.zero; 202 } 203 else if (tangentMode == TangentMode.Continuous && !isEndpoint) 204 { 205 var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero; 206 var isRightLinear = controlPoint.localRightTangent == Vector3.zero; 207 var tangentDotProduct = Vector3.Dot(controlPoint.localLeftTangent.normalized, controlPoint.localRightTangent.normalized); 208 var isContinous = tangentDotProduct < 0f && (tangentDotProduct + 1) < 0.001f; 209 var isLinear = isLeftLinear && isRightLinear; 210 211 if ((isLinear || oldTangentMode == TangentMode.Broken) && !isContinous) 212 { 213 var prevPoint = path.GetPrevPoint(index); 214 var nextPoint = path.GetNextPoint(index); 215 var vLeft = prevPoint.position - controlPoint.position; 216 var vRight = nextPoint.position - controlPoint.position; 217 var rightDirection = Vector3.Cross(Vector3.Cross(vLeft, vRight), vLeft.normalized + vRight.normalized).normalized; 218 var scale = 1f / 3f; 219 220 if (isLeftLinear) 221 controlPoint.localLeftTangent = vLeft.magnitude * scale * -rightDirection; 222 else 223 controlPoint.localLeftTangent = controlPoint.localLeftTangent.magnitude * -rightDirection; 224 225 if (isRightLinear) 226 controlPoint.localRightTangent = vRight.magnitude * scale * rightDirection; 227 else 228 controlPoint.localRightTangent = controlPoint.localRightTangent.magnitude * rightDirection; 229 } 230 } 231 else 232 { 233 var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero; 234 var isRightLinear = controlPoint.localRightTangent == Vector3.zero; 235 236 if (isLeftLinear || isRightLinear) 237 { 238 if (isLeftLinear) 239 controlPoint.localLeftTangent = path.CalculateLocalLeftTangent(index); 240 241 if (isRightLinear) 242 controlPoint.localRightTangent = path.CalculateLocalRightTangent(index); 243 } 244 } 245 246 controlPoint.StoreTangents(); 247 path.SetPoint(index, controlPoint); 248 path.localToWorldMatrix = localToWorldMatrix; 249 } 250 251 public static void MirrorTangent(this IEditablePath path, int index) 252 { 253 var localToWorldMatrix = path.localToWorldMatrix; 254 path.localToWorldMatrix = Matrix4x4.identity; 255 256 var controlPoint = path.GetPoint(index); 257 258 if (controlPoint.tangentMode == TangentMode.Linear) 259 return; 260 261 if (!Mathf.Approximately((controlPoint.localLeftTangent + controlPoint.localRightTangent).sqrMagnitude, 0f)) 262 { 263 if (controlPoint.mirrorLeft) 264 controlPoint.localLeftTangent = -controlPoint.localRightTangent; 265 else 266 controlPoint.localRightTangent = -controlPoint.localLeftTangent; 267 268 controlPoint.StoreTangents(); 269 path.SetPoint(index, controlPoint); 270 } 271 272 path.localToWorldMatrix = localToWorldMatrix; 273 } 274 } 275}