No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpriteShapeControllerEditor.cs 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.U2D;
  6. using UnityEditor;
  7. using UnityEditor.U2D.SpriteShapeInternal;
  8. using UnityEditor.U2D.Common;
  9. using UnityEditor.AnimatedValues;
  10. using UnityEditor.EditorTools;
  11. using UnityEditor.Overlays;
  12. using UnityEditor.U2D.Common.Path;
  13. using UnityEngine.SceneManagement;
  14. using Object = UnityEngine.Object;
  15. namespace UnityEditor.U2D
  16. {
  17. [CustomEditor(typeof(SpriteShapeController))]
  18. [CanEditMultipleObjects]
  19. internal class SpriteShapeControllerEditor : PathComponentEditor<CustomPath>
  20. {
  21. private static class Contents
  22. {
  23. public static readonly GUIContent splineLabel = new GUIContent("Spline");
  24. public static readonly string editSplineLabel = "Edit Spline";
  25. public static readonly GUIContent fillLabel = new GUIContent("Fill");
  26. public static readonly GUIContent colliderLabel = new GUIContent("Collider");
  27. public static readonly GUIContent shadowLabel = new GUIContent("Shadow");
  28. public static readonly GUIContent customGeometryLabel = new GUIContent("Custom Geometry");
  29. public static readonly GUIContent fillPixelPerUnitLabel = new GUIContent("Pixel Per Unit", "Pixel Per Unit for fill texture.");
  30. public static readonly GUIContent spriteShapeProfile = new GUIContent("Profile", "The SpriteShape Profile to render");
  31. public static readonly GUIContent materialLabel = new GUIContent("Material", "Material to be used by SpriteRenderer");
  32. public static readonly GUIContent colorLabel = new GUIContent("Color", "Rendering color for the Sprite graphic");
  33. public static readonly GUIContent metaDataLabel = new GUIContent("Meta Data", "SpriteShape specific controlpoint data");
  34. public static readonly GUIContent showComponentsLabel = new GUIContent("Show Render Stuff", "Show Renderer Components.");
  35. public static readonly GUIContent[] splineDetailOptions = { new GUIContent("High Quality"), new GUIContent("Medium Quality"), new GUIContent("Low Quality") };
  36. public static readonly GUIContent splineDetail = new GUIContent("Detail", "Tessellation Quality for rendering.");
  37. public static readonly GUIContent openEndedLabel = new GUIContent("Open Ended", "Is the path open ended or closed.");
  38. public static readonly GUIContent adaptiveUVLabel = new GUIContent("Adaptive UV", "Allow Adaptive UV Generation");
  39. public static readonly GUIContent enableTangentsLabel = new GUIContent("Enable Tangents", "Enable Tangents for 2D Lighting.");
  40. public static readonly GUIContent worldUVLabel = new GUIContent("Worldspace UV", "Generate UV for world space.");
  41. public static readonly GUIContent stretchUVLabel = new GUIContent("Stretch UV", "Stretch the Fill UV to full Rect.");
  42. public static readonly GUIContent stretchTilingLabel = new GUIContent("Stretch Tiling", "Stretch Tiling Count.");
  43. public static readonly GUIContent colliderDetail = new GUIContent("Detail", "Tessellation Quality on the collider.");
  44. public static readonly GUIContent cornerThresholdDetail = new GUIContent("Corner Threshold", "Corner angle threshold below which corners wont be placed.");
  45. public static readonly GUIContent colliderOffset = new GUIContent("Offset", "Extrude collider distance.");
  46. public static readonly GUIContent updateColliderLabel = new GUIContent("Update Collider", "Update Collider as you edit SpriteShape");
  47. public static readonly GUIContent shadowDetail = new GUIContent("Detail", "Tessellation Quality on the Shadow.");
  48. public static readonly GUIContent shadowOffset = new GUIContent("Offset", "Extrude shadow distance.");
  49. public static readonly GUIContent updateShadowLabel = new GUIContent("Update Shadow", "Update Shadow as you edit SpriteShape");
  50. public static readonly GUIContent optimizeColliderLabel = new GUIContent("Optimize Collider", "Cleanup planar self-intersections and optimize collider points");
  51. public static readonly GUIContent optimizeGeometryLabel = new GUIContent("Optimize Geometry", "Simplify geometry");
  52. public static readonly GUIContent cacheGeometryLabel = new GUIContent("Cache Geometry", "Bake geometry data. This will save geometry data on editor and load it on runtime instead of generating.");
  53. public static readonly GUIContent uTess2DLabel = new GUIContent("Fill Tessellation (C# Job)", "Use C# Jobs to generate Fill Geometry. (Edge geometry always uses C# Jobs)");
  54. public static readonly GUIContent creatorLabel = new GUIContent("Creator", "Allows over-riding default geometry calculations with a custom one.");
  55. public static readonly GUIContent modifiersLabel = new GUIContent("Modifier", "Allows processing / modifying generated vertices geometry.");
  56. public static readonly GUIContent boundsScaleLabel = new GUIContent("Bounds Scale", "Scale the Bounding Box of SpriteShape Geometry so its not culled out when scripting or dyanmically modifying Splines.");
  57. }
  58. private SerializedProperty m_SpriteShapeProp;
  59. private SerializedProperty m_SplineDetailProp;
  60. private SerializedProperty m_IsOpenEndedProp;
  61. private SerializedProperty m_AdaptiveUVProp;
  62. private SerializedProperty m_StretchUVProp;
  63. private SerializedProperty m_StretchTilingProp;
  64. private SerializedProperty m_WorldSpaceUVProp;
  65. private SerializedProperty m_FillPixelPerUnitProp;
  66. private SerializedProperty m_CornerAngleThresholdProp;
  67. private SerializedProperty m_ColliderAutoUpdate;
  68. private SerializedProperty m_ColliderDetailProp;
  69. private SerializedProperty m_ColliderOffsetProp;
  70. private SerializedProperty m_ShadowAutoUpdate;
  71. private SerializedProperty m_ShadowDetailProp;
  72. private SerializedProperty m_BoundsScaleProp;
  73. private SerializedProperty m_EnableTangentsProp;
  74. private SerializedProperty m_GeometryCachedProp;
  75. private SerializedProperty m_UTess2DGeometryProp;
  76. private SerializedProperty m_CreatorProp;
  77. private SerializedProperty m_ModifierListProp;
  78. public static SpriteShapeControllerEditor spriteshapeControllerEditor;
  79. private int m_CollidersCount = 0;
  80. private int[] m_QualityValues = new int[] { (int)QualityDetail.High, (int)QualityDetail.Mid, (int)QualityDetail.Low };
  81. readonly AnimBool m_ShowStretchOption = new AnimBool();
  82. readonly AnimBool m_ShowNonStretchOption = new AnimBool();
  83. private struct ShapeSegment
  84. {
  85. public int start;
  86. public int end;
  87. public int angleRange;
  88. };
  89. private struct ShapeAngleRange
  90. {
  91. public float start;
  92. public float end;
  93. public int order;
  94. public int index;
  95. };
  96. int m_ButtonSize = 4;
  97. int m_SelectedPoint = -1;
  98. int m_SelectedAngleRange = -1;
  99. int m_SpriteShapeHashCode = 0;
  100. int m_SplineHashCode = 0;
  101. List<ShapeSegment> m_ShapeSegments = new List<ShapeSegment>();
  102. SpriteSelector spriteSelector = new SpriteSelector();
  103. private SpriteShapeController m_SpriteShapeController
  104. {
  105. get { return target as SpriteShapeController; }
  106. }
  107. private void OnEnable()
  108. {
  109. if (target == null)
  110. return;
  111. m_SpriteShapeProp = serializedObject.FindProperty("m_SpriteShape");
  112. m_SplineDetailProp = serializedObject.FindProperty("m_SplineDetail");
  113. m_IsOpenEndedProp = serializedObject.FindProperty("m_Spline").FindPropertyRelative("m_IsOpenEnded");
  114. m_AdaptiveUVProp = serializedObject.FindProperty("m_AdaptiveUV");
  115. m_StretchUVProp = serializedObject.FindProperty("m_StretchUV");
  116. m_StretchTilingProp = serializedObject.FindProperty("m_StretchTiling");
  117. m_WorldSpaceUVProp = serializedObject.FindProperty("m_WorldSpaceUV");
  118. m_FillPixelPerUnitProp = serializedObject.FindProperty("m_FillPixelPerUnit");
  119. m_CornerAngleThresholdProp = serializedObject.FindProperty("m_CornerAngleThreshold");
  120. m_ColliderAutoUpdate = serializedObject.FindProperty("m_UpdateCollider");
  121. m_ShadowAutoUpdate = serializedObject.FindProperty("m_UpdateShadow");
  122. m_ColliderDetailProp = serializedObject.FindProperty("m_ColliderDetail");
  123. m_ColliderOffsetProp = serializedObject.FindProperty("m_ColliderOffset");
  124. m_ShadowDetailProp = serializedObject.FindProperty("m_ShadowDetail");
  125. m_BoundsScaleProp = serializedObject.FindProperty("m_BoundsScale");
  126. m_EnableTangentsProp = serializedObject.FindProperty("m_EnableTangents");
  127. m_GeometryCachedProp = serializedObject.FindProperty("m_GeometryCached");
  128. m_UTess2DGeometryProp = serializedObject.FindProperty("m_UTess2D");
  129. m_CreatorProp = serializedObject.FindProperty("m_Creator");
  130. m_ModifierListProp = serializedObject.FindProperty("m_Modifiers");
  131. m_ShowStretchOption.valueChanged.AddListener(Repaint);
  132. m_ShowStretchOption.value = ShouldShowStretchOption();
  133. m_ShowNonStretchOption.valueChanged.AddListener(Repaint);
  134. m_ShowNonStretchOption.value = !ShouldShowStretchOption();
  135. m_CollidersCount += ((m_SpriteShapeController.edgeCollider != null) ? 1 : 0);
  136. m_CollidersCount += ((m_SpriteShapeController.polygonCollider != null) ? 1 : 0);
  137. spriteshapeControllerEditor = this;
  138. }
  139. private void OnDisable()
  140. {
  141. SpriteShapeUpdateCache.UpdateCache(targets);
  142. spriteshapeControllerEditor = null;
  143. }
  144. private bool OnCollidersAddedOrRemoved()
  145. {
  146. PolygonCollider2D polygonCollider = m_SpriteShapeController.polygonCollider;
  147. EdgeCollider2D edgeCollider = m_SpriteShapeController.edgeCollider;
  148. int collidersCount = 0;
  149. if (polygonCollider != null)
  150. collidersCount = collidersCount + 1;
  151. if (edgeCollider != null)
  152. collidersCount = collidersCount + 1;
  153. if (collidersCount != m_CollidersCount)
  154. {
  155. m_CollidersCount = collidersCount;
  156. return true;
  157. }
  158. return false;
  159. }
  160. public void DrawHeader(GUIContent content)
  161. {
  162. EditorGUILayout.LabelField(content, EditorStyles.boldLabel);
  163. }
  164. private bool ShouldShowStretchOption()
  165. {
  166. return m_StretchUVProp.boolValue;
  167. }
  168. static bool WithinRange(ShapeAngleRange angleRange, float inputAngle)
  169. {
  170. float range = angleRange.end - angleRange.start;
  171. float angle = Mathf.Repeat(inputAngle - angleRange.start, 360f);
  172. angle = (angle == 360.0f) ? 0 : angle;
  173. return (angle >= 0f && angle <= range);
  174. }
  175. static int RangeFromAngle(List<ShapeAngleRange> angleRanges, float angle)
  176. {
  177. foreach (var range in angleRanges)
  178. {
  179. if (WithinRange(range, angle))
  180. return range.index;
  181. }
  182. return -1;
  183. }
  184. private List<ShapeAngleRange> GetAngleRangeSorted(UnityEngine.U2D.SpriteShape ss)
  185. {
  186. List<ShapeAngleRange> angleRanges = new List<ShapeAngleRange>();
  187. int i = 0;
  188. foreach (var angleRange in ss.angleRanges)
  189. {
  190. ShapeAngleRange sar = new ShapeAngleRange() { start = angleRange.start, end = angleRange.end, order = angleRange.order, index = i };
  191. angleRanges.Add(sar);
  192. i++;
  193. }
  194. angleRanges.Sort((a, b) => a.order.CompareTo(b.order));
  195. return angleRanges;
  196. }
  197. private void GenerateSegments(SpriteShapeController sc, List<ShapeAngleRange> angleRanges)
  198. {
  199. var controlPointCount = sc.spline.GetPointCount();
  200. var angleRangeIndices = new int[controlPointCount];
  201. ShapeSegment activeSegment = new ShapeSegment() { start = -1, end = -1, angleRange = -1 };
  202. m_ShapeSegments.Clear();
  203. for (int i = 0; i < controlPointCount; ++i)
  204. {
  205. var actv = i;
  206. var next = SplineUtility.NextIndex(actv, controlPointCount);
  207. var pos1 = sc.spline.GetPosition(actv);
  208. var pos2 = sc.spline.GetPosition(next);
  209. bool continueStrip = (sc.spline.GetTangentMode(actv) == ShapeTangentMode.Continuous), edgeUpdated = false;
  210. float angle = 0;
  211. if (false == continueStrip || activeSegment.start == -1)
  212. angle = SplineUtility.SlopeAngle(pos1, pos2) + 90.0f;
  213. next = (!sc.spline.isOpenEnded && next == 0) ? (actv + 1) : next;
  214. int mn = (actv < next) ? actv : next;
  215. int mx = (actv > next) ? actv : next;
  216. var anglerange = RangeFromAngle(angleRanges, angle);
  217. angleRangeIndices[actv] = anglerange;
  218. if (anglerange == -1)
  219. {
  220. activeSegment = new ShapeSegment() { start = mn, end = mx, angleRange = anglerange };
  221. m_ShapeSegments.Add(activeSegment);
  222. continue;
  223. }
  224. // Check for Segments. Also check if the Segment Start has been resolved. Otherwise simply start with the next one
  225. if (activeSegment.start != -1)
  226. continueStrip = continueStrip && (angleRangeIndices[activeSegment.start] != -1);
  227. bool canContinue = (actv != (controlPointCount - 1)) || (!sc.spline.isOpenEnded && (actv == (controlPointCount - 1)));
  228. if (continueStrip && canContinue)
  229. {
  230. for (int s = 0; s < m_ShapeSegments.Count; ++s)
  231. {
  232. activeSegment = m_ShapeSegments[s];
  233. if (activeSegment.start - mn == 1)
  234. {
  235. edgeUpdated = true;
  236. activeSegment.start = mn;
  237. m_ShapeSegments[s] = activeSegment;
  238. break;
  239. }
  240. if (mx - activeSegment.end == 1)
  241. {
  242. edgeUpdated = true;
  243. activeSegment.end = mx;
  244. m_ShapeSegments[s] = activeSegment;
  245. break;
  246. }
  247. }
  248. }
  249. if (!edgeUpdated)
  250. {
  251. activeSegment.start = mn;
  252. activeSegment.end = mx;
  253. activeSegment.angleRange = anglerange;
  254. m_ShapeSegments.Add(activeSegment);
  255. }
  256. }
  257. }
  258. private int GetAngleRange(SpriteShapeController sc, int point, ref int startPoint)
  259. {
  260. int angleRange = -1;
  261. startPoint = point;
  262. for (int i = 0; i < m_ShapeSegments.Count; ++i)
  263. {
  264. if (point >= m_ShapeSegments[i].start && point < m_ShapeSegments[i].end)
  265. {
  266. angleRange = m_ShapeSegments[i].angleRange;
  267. startPoint = point; // m_ShapeSegments[i].start;
  268. if (angleRange >= sc.spriteShape.angleRanges.Count)
  269. angleRange = 0;
  270. break;
  271. }
  272. }
  273. return angleRange;
  274. }
  275. private void UpdateSegments()
  276. {
  277. var sc = target as SpriteShapeController;
  278. // Either SpriteShape Asset or SpriteShape Data has changed.
  279. if (m_SpriteShapeHashCode != sc.spriteShapeHashCode || m_SplineHashCode != sc.splineHashCode)
  280. {
  281. List<ShapeAngleRange> angleRanges = GetAngleRangeSorted(sc.spriteShape);
  282. GenerateSegments(sc, angleRanges);
  283. m_SpriteShapeHashCode = sc.spriteShapeHashCode;
  284. m_SplineHashCode = sc.splineHashCode;
  285. m_SelectedPoint = -1;
  286. }
  287. }
  288. private int ResolveSpriteIndex(List<int> spriteIndices, ISelection<int> selection, ref List<int> startPoints)
  289. {
  290. var spriteIndexValue = spriteIndices.FirstOrDefault();
  291. var sc = target as SpriteShapeController;
  292. var spline = sc.spline;
  293. if (sc == null || sc.spriteShape == null)
  294. return -1;
  295. UpdateSegments();
  296. if (sc.spriteShape != null)
  297. {
  298. if (selection.Count == 1)
  299. {
  300. m_SelectedAngleRange = GetAngleRange(sc, selection.elements[0], ref m_SelectedPoint);
  301. startPoints.Add(m_SelectedPoint);
  302. spriteIndexValue = spline.GetSpriteIndex(m_SelectedPoint);
  303. }
  304. else
  305. {
  306. m_SelectedAngleRange = -1;
  307. foreach (var index in selection.elements)
  308. {
  309. int startPoint = index;
  310. int angleRange = GetAngleRange(sc, index, ref startPoint);
  311. if (m_SelectedAngleRange != -1 && angleRange != m_SelectedAngleRange)
  312. {
  313. m_SelectedAngleRange = -1;
  314. break;
  315. }
  316. startPoints.Add(startPoint);
  317. m_SelectedAngleRange = angleRange;
  318. }
  319. }
  320. }
  321. if (m_SelectedAngleRange != -1)
  322. spriteSelector.UpdateSprites(sc.spriteShape.angleRanges[m_SelectedAngleRange].sprites.ToArray());
  323. else
  324. spriteIndexValue = -1;
  325. return spriteIndexValue;
  326. }
  327. public int GetAngleRange(int index)
  328. {
  329. int startPoint = 0;
  330. var sc = target as SpriteShapeController;
  331. UpdateSegments();
  332. return GetAngleRange(sc, index, ref startPoint);
  333. }
  334. public void OnOverlayGUI()
  335. {
  336. var pathTool = SpriteShapeEditorTool.activeSpriteShapeEditorTool;
  337. serializedObject.Update();
  338. DoPathInspector<SpriteShapeEditorTool>();
  339. if (Selection.gameObjects.Length == 1 && pathTool != null)
  340. {
  341. var sc = target as SpriteShapeController;
  342. var path = pathTool.GetPath(sc);
  343. if (path != null)
  344. {
  345. var selection = path.selection;
  346. if (selection.Count > 0)
  347. {
  348. var spline = sc.spline;
  349. var spriteIndices = new List<int>();
  350. List<int> startPoints = new List<int>();
  351. foreach (int index in selection.elements)
  352. spriteIndices.Add(spline.GetSpriteIndex(index));
  353. var spriteIndexValue = ResolveSpriteIndex(spriteIndices, selection, ref startPoints);
  354. if (spriteIndexValue != -1)
  355. {
  356. EditorGUI.BeginChangeCheck();
  357. spriteSelector.SetCustomSize(0, m_ButtonSize);
  358. bool shown = spriteSelector.ShowGUI(spriteIndexValue);
  359. spriteSelector.ResetSize();
  360. if (EditorGUI.EndChangeCheck())
  361. {
  362. foreach (var index in startPoints)
  363. {
  364. var data = path.GetData(index);
  365. data.spriteIndex = spriteSelector.selectedIndex;
  366. path.SetData(index, data);
  367. }
  368. pathTool.SetPath(target);
  369. }
  370. if (spriteSelector.hasSprites)
  371. m_ButtonSize = (int)GUI.HorizontalSlider(new Rect(InternalEditorBridge.GetEditorGUILayoutLastRect().width - 64, InternalEditorBridge.GetEditorGUILayoutLastRect().y + 100, 64, 100 ), m_ButtonSize, 1, 4);
  372. }
  373. EditorGUILayout.Space();
  374. }
  375. }
  376. }
  377. serializedObject.ApplyModifiedProperties();
  378. }
  379. public override void OnInspectorGUI()
  380. {
  381. var updateCollider = false;
  382. EditorGUI.BeginChangeCheck();
  383. serializedObject.Update();
  384. EditorGUILayout.PropertyField(m_SpriteShapeProp, Contents.spriteShapeProfile);
  385. DoEditButton<SpriteShapeEditorTool>(PathEditorToolContents.icon, Contents.editSplineLabel);
  386. EditorGUILayout.Space();
  387. DrawHeader(Contents.splineLabel);
  388. EditorGUILayout.IntPopup(m_SplineDetailProp, Contents.splineDetailOptions, m_QualityValues, Contents.splineDetail);
  389. EditorGUILayout.PropertyField(m_BoundsScaleProp, Contents.boundsScaleLabel);
  390. serializedObject.ApplyModifiedProperties();
  391. DoOpenEndedInspector<SpriteShapeEditorTool>(m_IsOpenEndedProp);
  392. serializedObject.Update();
  393. EditorGUILayout.PropertyField(m_AdaptiveUVProp, Contents.adaptiveUVLabel);
  394. EditorGUILayout.PropertyField(m_EnableTangentsProp, Contents.enableTangentsLabel);
  395. // Cache Geometry is only editable for Scene Objects or when in Prefab Isolation Mode.
  396. {
  397. bool cacheEnabled = (Selection.gameObjects.Length == 1 && Selection.transforms.Contains(Selection.gameObjects[0].transform) && UnityEditor.EditorTools.ToolManager.activeToolType == typeof(SpriteShapeEditorTool));
  398. EditorGUI.BeginDisabledGroup(cacheEnabled == false);
  399. {
  400. EditorGUI.BeginChangeCheck();
  401. EditorGUILayout.PropertyField(m_GeometryCachedProp, Contents.cacheGeometryLabel);
  402. if (EditorGUI.EndChangeCheck())
  403. {
  404. if (m_GeometryCachedProp.boolValue)
  405. {
  406. var geometryCache = m_SpriteShapeController.spriteShapeGeometryCache;
  407. if (!geometryCache)
  408. geometryCache = m_SpriteShapeController.gameObject
  409. .AddComponent<SpriteShapeGeometryCache>();
  410. geometryCache.hideFlags = HideFlags.HideInInspector;
  411. }
  412. else
  413. {
  414. if (m_SpriteShapeController.spriteShapeGeometryCache)
  415. Object.DestroyImmediate(m_SpriteShapeController.spriteShapeGeometryCache);
  416. }
  417. m_SpriteShapeController.RefreshSpriteShape();
  418. }
  419. }
  420. EditorGUI.EndDisabledGroup();
  421. SpriteShapeUpdateCache.s_cacheGeometrySet = true;
  422. }
  423. EditorGUI.BeginChangeCheck();
  424. var threshold = EditorGUILayout.Slider(Contents.cornerThresholdDetail, m_CornerAngleThresholdProp.floatValue, 0.0f, 90.0f);
  425. if (EditorGUI.EndChangeCheck())
  426. {
  427. m_CornerAngleThresholdProp.floatValue = threshold;
  428. updateCollider = true;
  429. }
  430. Debug.Assert(null != m_SpriteShapeController.spriteShapeCreator);
  431. EditorGUILayout.Space();
  432. DrawHeader(Contents.fillLabel);
  433. EditorGUILayout.PropertyField(m_UTess2DGeometryProp, Contents.uTess2DLabel);
  434. EditorGUILayout.PropertyField(m_StretchUVProp, Contents.stretchUVLabel);
  435. if (ShouldShowStretchOption())
  436. {
  437. EditorGUILayout.PropertyField(m_StretchTilingProp, Contents.stretchTilingLabel);
  438. }
  439. else
  440. {
  441. EditorGUILayout.PropertyField(m_FillPixelPerUnitProp, Contents.fillPixelPerUnitLabel);
  442. EditorGUILayout.PropertyField(m_WorldSpaceUVProp, Contents.worldUVLabel);
  443. }
  444. EditorGUILayout.Space();
  445. DrawHeader(Contents.customGeometryLabel);
  446. EditorGUILayout.PropertyField(m_CreatorProp, Contents.creatorLabel);
  447. EditorGUILayout.PropertyField(m_ModifierListProp, Contents.modifiersLabel);
  448. if (m_SpriteShapeController.gameObject.GetComponent<PolygonCollider2D>() != null || m_SpriteShapeController.gameObject.GetComponent<EdgeCollider2D>() != null)
  449. {
  450. EditorGUILayout.Space();
  451. DrawHeader(Contents.colliderLabel);
  452. EditorGUILayout.PropertyField(m_ColliderAutoUpdate, Contents.updateColliderLabel);
  453. if (m_ColliderAutoUpdate.boolValue)
  454. {
  455. EditorGUILayout.PropertyField(m_ColliderOffsetProp, Contents.colliderOffset);
  456. EditorGUILayout.IntPopup(m_ColliderDetailProp, Contents.splineDetailOptions, m_QualityValues, Contents.colliderDetail);
  457. }
  458. }
  459. if (m_ShadowAutoUpdate.boolValue)
  460. {
  461. EditorGUILayout.Space();
  462. DrawHeader(Contents.shadowLabel);
  463. EditorGUILayout.IntPopup(m_ShadowDetailProp, Contents.splineDetailOptions, m_QualityValues, Contents.shadowDetail);
  464. }
  465. if (EditorGUI.EndChangeCheck())
  466. {
  467. updateCollider = true;
  468. }
  469. serializedObject.ApplyModifiedProperties();
  470. if (updateCollider || OnCollidersAddedOrRemoved())
  471. BakeCollider();
  472. }
  473. void BakeCollider()
  474. {
  475. if (m_SpriteShapeController.autoUpdateCollider == false && !m_SpriteShapeController.updateShadow)
  476. return;
  477. PolygonCollider2D polygonCollider = m_SpriteShapeController.polygonCollider;
  478. if (polygonCollider)
  479. {
  480. Undo.RegisterCompleteObjectUndo(polygonCollider, Undo.GetCurrentGroupName());
  481. EditorUtility.SetDirty(polygonCollider);
  482. m_SpriteShapeController.RefreshSpriteShape();
  483. }
  484. EdgeCollider2D edgeCollider = m_SpriteShapeController.edgeCollider;
  485. if (edgeCollider)
  486. {
  487. Undo.RegisterCompleteObjectUndo(edgeCollider, Undo.GetCurrentGroupName());
  488. EditorUtility.SetDirty(edgeCollider);
  489. m_SpriteShapeController.RefreshSpriteShape();
  490. }
  491. }
  492. void ShowMaterials(bool show)
  493. {
  494. HideFlags hideFlags = HideFlags.HideInInspector;
  495. if (show)
  496. hideFlags = HideFlags.None;
  497. Material[] materials = m_SpriteShapeController.spriteShapeRenderer.sharedMaterials;
  498. foreach (Material material in materials)
  499. {
  500. material.hideFlags = hideFlags;
  501. EditorUtility.SetDirty(material);
  502. }
  503. }
  504. [DrawGizmo(GizmoType.InSelectionHierarchy)]
  505. static void RenderSpline(SpriteShapeController m_SpriteShapeController, GizmoType gizmoType)
  506. {
  507. if (UnityEditor.EditorTools.ToolManager.activeToolType == typeof(SpriteShapeEditorTool))
  508. return;
  509. var m_Spline = m_SpriteShapeController.spline;
  510. var oldMatrix = Handles.matrix;
  511. var oldColor = Handles.color;
  512. Handles.matrix = m_SpriteShapeController.transform.localToWorldMatrix;
  513. Handles.color = Color.grey;
  514. var pointCount = m_Spline.GetPointCount();
  515. for (var i = 0; i < (m_Spline.isOpenEnded ? pointCount - 1 : pointCount); ++i)
  516. {
  517. Vector3 p1 = m_Spline.GetPosition(i);
  518. Vector3 p2 = m_Spline.GetPosition((i + 1) % pointCount);
  519. var t1 = p1 + m_Spline.GetRightTangent(i);
  520. var t2 = p2 + m_Spline.GetLeftTangent((i + 1) % pointCount);
  521. Vector3[] bezierPoints = Handles.MakeBezierPoints(p1, p2, t1, t2, m_SpriteShapeController.splineDetail);
  522. Handles.DrawAAPolyLine(bezierPoints);
  523. }
  524. Handles.matrix = oldMatrix;
  525. Handles.color = oldColor;
  526. }
  527. }
  528. [Overlay(typeof(SceneView), k_OverlayId, k_DisplayName)]
  529. class SceneViewPathOverlay : IMGUIOverlay, ITransientOverlay
  530. {
  531. const string k_OverlayId = "Scene View/Path";
  532. const string k_DisplayName = "Element Inspector";
  533. public bool visible
  534. {
  535. get
  536. {
  537. var pathTool = SpriteShapeEditorTool.activeSpriteShapeEditorTool;
  538. var valid= SpriteShapeControllerEditor.spriteshapeControllerEditor != null && pathTool != null;
  539. if (valid)
  540. {
  541. if (pathTool.targets != null)
  542. {
  543. foreach (var t in pathTool.targets)
  544. {
  545. var s = pathTool.GetPath(t);
  546. if (null != s && s.selection.Count != 0)
  547. return true;
  548. }
  549. }
  550. else if (pathTool.target != null)
  551. {
  552. var s1 = pathTool.GetPath(pathTool.target);
  553. if (null != s1 && s1.selection.Count != 0)
  554. return true;
  555. }
  556. }
  557. return false;
  558. }
  559. }
  560. public override void OnGUI()
  561. {
  562. if (SpriteShapeControllerEditor.spriteshapeControllerEditor == null)
  563. return;
  564. SpriteShapeControllerEditor.spriteshapeControllerEditor.OnOverlayGUI();
  565. }
  566. }
  567. [UnityEditor.InitializeOnLoad]
  568. internal static class SpriteShapeUpdateCache
  569. {
  570. internal static bool s_cacheGeometrySet = false;
  571. static SpriteShapeUpdateCache()
  572. {
  573. UnityEditor.EditorApplication.playModeStateChanged += change =>
  574. {
  575. if (change == UnityEditor.PlayModeStateChange.ExitingEditMode)
  576. UpdateSpriteShapeCacheInOpenScenes();
  577. };
  578. SceneManagement.EditorSceneManager.sceneSaving += (scene, removingScene) =>
  579. {
  580. SaveSpriteShapesInScene(scene);
  581. };
  582. UnityEditor.EditorTools.ToolManager.activeToolChanging += () =>
  583. {
  584. if (UnityEditor.EditorTools.ToolManager.activeToolType == typeof(SpriteShapeEditorTool))
  585. {
  586. if (null != SpriteShapeControllerEditor.spriteshapeControllerEditor)
  587. UpdateCache(SpriteShapeControllerEditor.spriteshapeControllerEditor.targets);
  588. }
  589. };
  590. }
  591. static void SaveSpriteShapesInScene(Scene scene)
  592. {
  593. var gos = scene.GetRootGameObjects();
  594. foreach (var go in gos)
  595. {
  596. if (!go.activeInHierarchy)
  597. continue;
  598. var scs = go.GetComponentsInChildren<SpriteShapeController>();
  599. foreach (var sc in scs)
  600. {
  601. var jh = sc.BakeMesh();
  602. jh.Complete();
  603. }
  604. }
  605. }
  606. static void UpdateSpriteShapeCacheInOpenScenes()
  607. {
  608. for (int i = 0; s_cacheGeometrySet && (i < SceneManager.sceneCount); ++i)
  609. {
  610. var scene = SceneManager.GetSceneAt(i);
  611. SaveSpriteShapesInScene(scene);
  612. }
  613. s_cacheGeometrySet = false;
  614. }
  615. internal static void UpdateCache(UnityEngine.Object[] targets)
  616. {
  617. foreach (var t in targets)
  618. {
  619. var s = t as SpriteShapeController;
  620. if (s)
  621. if (s.gameObject.activeInHierarchy && s.spriteShapeGeometryCache)
  622. s.spriteShapeGeometryCache.UpdateGeometryCache();
  623. }
  624. }
  625. }
  626. }