SpriteMeshView.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. using UnityEngine;
  2. namespace UnityEditor.U2D.Animation
  3. {
  4. internal class SpriteMeshView : ISpriteMeshView
  5. {
  6. readonly int m_VertexHashCode = "Vertex".GetHashCode();
  7. readonly int m_EdgeHashCode = "Edge".GetHashCode();
  8. const string kDeleteCommandName = "Delete";
  9. const string kSoftDeleteCommandName = "SoftDelete";
  10. static readonly Color kEdgeColor = Color.cyan;
  11. static readonly Color kEdgeHoveredColor = Color.yellow;
  12. static readonly Color kEdgeSelectedColor = Color.yellow;
  13. const float kEdgeWidth = 2f;
  14. const float kVertexRadius = 2.5f;
  15. private class Styles
  16. {
  17. public readonly GUIStyle pointNormalStyle;
  18. public readonly GUIStyle pointHoveredStyle;
  19. public readonly GUIStyle pointSelectedStyle;
  20. public Styles()
  21. {
  22. Texture2D pointNormal = ResourceLoader.Load<Texture2D>("SkinningModule/dotCyan.png");
  23. Texture2D pointHovered = ResourceLoader.Load<Texture2D>("SkinningModule/dotYellow.png");
  24. Texture2D pointSelected = ResourceLoader.Load<Texture2D>("SkinningModule/dotYellow.png");
  25. pointNormalStyle = new GUIStyle();
  26. pointNormalStyle.normal.background = pointNormal;
  27. pointNormalStyle.fixedWidth = 8f;
  28. pointNormalStyle.fixedHeight = 8f;
  29. pointHoveredStyle = new GUIStyle();
  30. pointHoveredStyle.normal.background = pointHovered;
  31. pointHoveredStyle.fixedWidth = 10f;
  32. pointHoveredStyle.fixedHeight = 10f;
  33. pointSelectedStyle = new GUIStyle();
  34. pointSelectedStyle.normal.background = pointSelected;
  35. pointSelectedStyle.fixedWidth = 10f;
  36. pointSelectedStyle.fixedHeight = 10f;
  37. }
  38. }
  39. private Styles m_Styles;
  40. private Styles styles
  41. {
  42. get
  43. {
  44. if (m_Styles == null)
  45. m_Styles = new Styles();
  46. return m_Styles;
  47. }
  48. }
  49. int m_HoveredEdge = -1;
  50. int m_HoveredEdgeControlID = -1;
  51. int m_MoveEdgeControlID = -1;
  52. int m_HoveredVertex = -1;
  53. int m_PrevHoveredVertex = -1;
  54. int m_HoveredVertexControlID = -1;
  55. int m_MoveVertexControlID = -1;
  56. Color m_TempColor;
  57. SliderData m_HotSliderData = SliderData.zero;
  58. MeshEditorAction m_PreviousActiveAction = MeshEditorAction.None;
  59. private Vector2 m_MouseWorldPosition;
  60. private float m_NearestVertexDistance;
  61. private float m_NearestEdgeDistance;
  62. private int m_NearestVertex = -1;
  63. private int m_NearestEdge = -1;
  64. public SpriteMeshViewMode mode { get; set; }
  65. public ISelection<int> selection { get; set; }
  66. public int defaultControlID { get; set; }
  67. public Rect frame { get; set; }
  68. private IGUIWrapper guiWrapper { get; set; }
  69. public Vector2 mouseWorldPosition
  70. {
  71. get { return m_MouseWorldPosition; }
  72. }
  73. public int hoveredVertex
  74. {
  75. get { return m_HoveredVertex; }
  76. }
  77. public int hoveredEdge
  78. {
  79. get { return m_HoveredEdge; }
  80. }
  81. public int closestEdge
  82. {
  83. get { return m_NearestEdge; }
  84. }
  85. public SpriteMeshView(IGUIWrapper gw)
  86. {
  87. guiWrapper = gw;
  88. }
  89. public void CancelMode()
  90. {
  91. if (mode != SpriteMeshViewMode.EditGeometry)
  92. {
  93. if (guiWrapper.IsKeyDown(KeyCode.Escape) || guiWrapper.IsMouseDown(1))
  94. {
  95. mode = SpriteMeshViewMode.EditGeometry;
  96. guiWrapper.UseCurrentEvent();
  97. }
  98. }
  99. }
  100. public void BeginLayout()
  101. {
  102. var vertexControlID = guiWrapper.GetControlID(m_VertexHashCode, FocusType.Passive);
  103. var edgeControlID = guiWrapper.GetControlID(m_EdgeHashCode, FocusType.Passive);
  104. if (guiWrapper.eventType == EventType.Layout || guiWrapper.eventType == EventType.MouseMove)
  105. {
  106. m_NearestVertexDistance = float.MaxValue;
  107. m_NearestEdgeDistance = float.MaxValue;
  108. m_NearestVertex = -1;
  109. m_NearestEdge = -1;
  110. m_MouseWorldPosition = guiWrapper.GUIToWorld(guiWrapper.mousePosition);
  111. m_HoveredVertexControlID = vertexControlID;
  112. m_HoveredEdgeControlID = edgeControlID;
  113. m_PrevHoveredVertex = m_HoveredVertex;
  114. m_HoveredVertex = -1;
  115. m_HoveredEdge = -1;
  116. if (guiWrapper.IsControlHot(0))
  117. {
  118. m_MoveVertexControlID = -1;
  119. m_MoveEdgeControlID = -1;
  120. }
  121. }
  122. }
  123. public void EndLayout()
  124. {
  125. guiWrapper.LayoutControl(m_HoveredEdgeControlID, m_NearestEdgeDistance);
  126. guiWrapper.LayoutControl(m_HoveredVertexControlID, m_NearestVertexDistance);
  127. if(guiWrapper.IsControlNearest(m_HoveredVertexControlID))
  128. m_HoveredVertex = m_NearestVertex;
  129. if (guiWrapper.IsControlNearest(m_HoveredEdgeControlID))
  130. m_HoveredEdge = m_NearestEdge;
  131. if (guiWrapper.eventType == EventType.Layout || guiWrapper.eventType == EventType.MouseMove)
  132. if (m_PrevHoveredVertex != m_HoveredVertex)
  133. guiWrapper.Repaint();
  134. }
  135. public void LayoutVertex(Vector2 position, int index)
  136. {
  137. if (guiWrapper.eventType == EventType.Layout)
  138. {
  139. var distance = guiWrapper.DistanceToCircle(position, kVertexRadius);
  140. if (distance <= m_NearestVertexDistance)
  141. {
  142. m_NearestVertexDistance = distance;
  143. m_NearestVertex = index;
  144. }
  145. }
  146. }
  147. public void LayoutEdge(Vector2 startPosition, Vector2 endPosition, int index)
  148. {
  149. if (guiWrapper.eventType == EventType.Layout)
  150. {
  151. var distance = guiWrapper.DistanceToSegment(startPosition, endPosition);
  152. if (distance < m_NearestEdgeDistance)
  153. {
  154. m_NearestEdgeDistance = distance;
  155. m_NearestEdge = index;
  156. }
  157. }
  158. }
  159. public bool DoCreateVertex()
  160. {
  161. if (mode == SpriteMeshViewMode.CreateVertex && IsActionActive(MeshEditorAction.CreateVertex))
  162. ConsumeMouseMoveEvents();
  163. if (IsActionTriggered(MeshEditorAction.CreateVertex))
  164. {
  165. guiWrapper.SetGuiChanged(true);
  166. guiWrapper.UseCurrentEvent();
  167. return true;
  168. }
  169. return false;
  170. }
  171. public bool DoSelectVertex(out bool additive)
  172. {
  173. additive = false;
  174. if (IsActionTriggered(MeshEditorAction.SelectVertex))
  175. {
  176. additive = guiWrapper.isActionKeyDown;
  177. guiWrapper.Repaint();
  178. return true;
  179. }
  180. return false;
  181. }
  182. public bool DoMoveVertex(out Vector2 delta)
  183. {
  184. delta = Vector2.zero;
  185. if (IsActionTriggered(MeshEditorAction.MoveVertex))
  186. {
  187. m_MoveVertexControlID = m_HoveredVertexControlID;
  188. m_HotSliderData.position = mouseWorldPosition;
  189. }
  190. Vector3 newPosition;
  191. if (guiWrapper.DoSlider(m_MoveVertexControlID, m_HotSliderData, out newPosition))
  192. {
  193. delta = newPosition - m_HotSliderData.position;
  194. m_HotSliderData.position = newPosition;
  195. return true;
  196. }
  197. return false;
  198. }
  199. public bool DoMoveEdge(out Vector2 delta)
  200. {
  201. delta = Vector2.zero;
  202. if (IsActionTriggered(MeshEditorAction.MoveEdge))
  203. {
  204. m_MoveEdgeControlID = m_HoveredEdgeControlID;
  205. m_HotSliderData.position = mouseWorldPosition;
  206. }
  207. Vector3 newPosition;
  208. if (guiWrapper.DoSlider(m_MoveEdgeControlID, m_HotSliderData, out newPosition))
  209. {
  210. delta = newPosition - m_HotSliderData.position;
  211. m_HotSliderData.position = newPosition;
  212. return true;
  213. }
  214. return false;
  215. }
  216. public bool DoCreateEdge()
  217. {
  218. if (IsActionActive(MeshEditorAction.CreateEdge))
  219. ConsumeMouseMoveEvents();
  220. if (IsActionTriggered(MeshEditorAction.CreateEdge))
  221. {
  222. guiWrapper.SetGuiChanged(true);
  223. guiWrapper.UseCurrentEvent();
  224. return true;
  225. }
  226. return false;
  227. }
  228. public bool DoSplitEdge()
  229. {
  230. if (IsActionActive(MeshEditorAction.SplitEdge))
  231. ConsumeMouseMoveEvents();
  232. if (IsActionTriggered(MeshEditorAction.SplitEdge))
  233. {
  234. guiWrapper.UseCurrentEvent();
  235. guiWrapper.SetGuiChanged(true);
  236. return true;
  237. }
  238. return false;
  239. }
  240. public bool DoSelectEdge(out bool additive)
  241. {
  242. additive = false;
  243. if (IsActionTriggered(MeshEditorAction.SelectEdge))
  244. {
  245. additive = guiWrapper.isActionKeyDown;
  246. guiWrapper.Repaint();
  247. return true;
  248. }
  249. return false;
  250. }
  251. public bool DoRemove()
  252. {
  253. if (IsActionTriggered(MeshEditorAction.Remove))
  254. {
  255. guiWrapper.UseCurrentEvent();
  256. guiWrapper.SetGuiChanged(true);
  257. return true;
  258. }
  259. return false;
  260. }
  261. public void DrawVertex(Vector2 position)
  262. {
  263. DrawingUtility.DrawGUIStyleCap(0, position, Quaternion.identity, 1f, styles.pointNormalStyle);
  264. }
  265. public void DrawVertexHovered(Vector2 position)
  266. {
  267. DrawingUtility.DrawGUIStyleCap(0, position, Quaternion.identity, 1f, styles.pointHoveredStyle);
  268. }
  269. public void DrawVertexSelected(Vector2 position)
  270. {
  271. DrawingUtility.DrawGUIStyleCap(0, position, Quaternion.identity, 1f, styles.pointSelectedStyle);
  272. }
  273. public void BeginDrawEdges()
  274. {
  275. if (guiWrapper.eventType != EventType.Repaint)
  276. return;
  277. DrawingUtility.BeginSolidLines();
  278. m_TempColor = Handles.color;
  279. }
  280. public void EndDrawEdges()
  281. {
  282. if (guiWrapper.eventType != EventType.Repaint)
  283. return;
  284. DrawingUtility.EndLines();
  285. Handles.color = m_TempColor;
  286. }
  287. public void DrawEdge(Vector2 startPosition, Vector2 endPosition)
  288. {
  289. DrawEdge(startPosition, endPosition, kEdgeColor);
  290. }
  291. public void DrawEdgeHovered(Vector2 startPosition, Vector2 endPosition)
  292. {
  293. DrawEdge(startPosition, endPosition, kEdgeHoveredColor);
  294. }
  295. public void DrawEdgeSelected(Vector2 startPosition, Vector2 endPosition)
  296. {
  297. DrawEdge(startPosition, endPosition, kEdgeSelectedColor);
  298. }
  299. public bool IsActionActive(MeshEditorAction action)
  300. {
  301. if (guiWrapper.isAltDown || !guiWrapper.IsControlHot(0))
  302. return false;
  303. var canCreateEdge = CanCreateEdge();
  304. var canSplitEdge = CanSplitEdge();
  305. if (action == MeshEditorAction.None)
  306. return guiWrapper.IsControlNearest(defaultControlID);
  307. if (action == MeshEditorAction.CreateVertex)
  308. {
  309. if(!frame.Contains(mouseWorldPosition))
  310. return false;
  311. if (mode == SpriteMeshViewMode.EditGeometry)
  312. return guiWrapper.IsControlNearest(defaultControlID);
  313. if (mode == SpriteMeshViewMode.CreateVertex)
  314. return hoveredVertex == -1;
  315. }
  316. if (action == MeshEditorAction.MoveVertex)
  317. return guiWrapper.IsControlNearest(m_HoveredVertexControlID);
  318. if (action == MeshEditorAction.CreateEdge)
  319. return canCreateEdge;
  320. if (action == MeshEditorAction.SplitEdge)
  321. return canSplitEdge;
  322. if (action == MeshEditorAction.MoveEdge)
  323. return guiWrapper.IsControlNearest(m_HoveredEdgeControlID);
  324. if (action == MeshEditorAction.SelectVertex)
  325. return guiWrapper.IsControlNearest(m_HoveredVertexControlID);
  326. if (action == MeshEditorAction.SelectEdge)
  327. return mode == SpriteMeshViewMode.EditGeometry &&
  328. guiWrapper.IsControlNearest(m_HoveredEdgeControlID) &&
  329. !canCreateEdge && !canSplitEdge;
  330. if (action == MeshEditorAction.Remove)
  331. return true;
  332. return false;
  333. }
  334. public bool IsActionHot(MeshEditorAction action)
  335. {
  336. if (action == MeshEditorAction.None)
  337. return guiWrapper.IsControlHot(0);
  338. if (action == MeshEditorAction.MoveVertex)
  339. return guiWrapper.IsControlHot(m_HoveredVertexControlID);
  340. if (action == MeshEditorAction.MoveEdge)
  341. return guiWrapper.IsControlHot(m_HoveredEdgeControlID);
  342. return false;
  343. }
  344. public bool IsActionTriggered(MeshEditorAction action)
  345. {
  346. if (!IsActionActive(action))
  347. return false;
  348. if (action == MeshEditorAction.CreateVertex)
  349. {
  350. if (mode == SpriteMeshViewMode.EditGeometry)
  351. return guiWrapper.IsMouseDown(0) && guiWrapper.clickCount == 2;
  352. }
  353. if (action == MeshEditorAction.Remove)
  354. {
  355. if ((guiWrapper.eventType == EventType.ValidateCommand || guiWrapper.eventType == EventType.ExecuteCommand)
  356. && (guiWrapper.commandName == kSoftDeleteCommandName || guiWrapper.commandName == kDeleteCommandName))
  357. {
  358. if (guiWrapper.eventType == EventType.ExecuteCommand)
  359. return true;
  360. guiWrapper.UseCurrentEvent();
  361. }
  362. return false;
  363. }
  364. if(action != MeshEditorAction.None)
  365. return guiWrapper.IsMouseDown(0);
  366. return false;
  367. }
  368. public Vector2 WorldToScreen(Vector2 position)
  369. {
  370. return HandleUtility.WorldToGUIPoint(position);
  371. }
  372. private void ConsumeMouseMoveEvents()
  373. {
  374. if (guiWrapper.eventType == EventType.MouseMove || (guiWrapper.eventType == EventType.MouseDrag && guiWrapper.mouseButton == 0))
  375. guiWrapper.UseCurrentEvent();
  376. }
  377. private bool CanCreateEdge()
  378. {
  379. if(!frame.Contains(mouseWorldPosition) || !(guiWrapper.IsControlNearest(defaultControlID) || guiWrapper.IsControlNearest(m_HoveredVertexControlID) || guiWrapper.IsControlNearest(m_HoveredEdgeControlID)))
  380. return false;
  381. if (mode == SpriteMeshViewMode.EditGeometry)
  382. return guiWrapper.isShiftDown && selection.Count == 1 && !selection.Contains(hoveredVertex);
  383. if (mode == SpriteMeshViewMode.CreateEdge)
  384. return selection.Count == 1 && !selection.Contains(hoveredVertex);
  385. return false;
  386. }
  387. private bool CanSplitEdge()
  388. {
  389. if(!frame.Contains(mouseWorldPosition) || !(guiWrapper.IsControlNearest(defaultControlID) || guiWrapper.IsControlNearest(m_HoveredEdgeControlID)))
  390. return false;
  391. if (mode == SpriteMeshViewMode.EditGeometry)
  392. return guiWrapper.isShiftDown && m_NearestEdge != -1 && hoveredVertex == -1 && selection.Count == 0;
  393. if (mode == SpriteMeshViewMode.SplitEdge)
  394. return m_NearestEdge != -1 && hoveredVertex == -1;
  395. return false;
  396. }
  397. private void DrawEdge(Vector2 startPosition, Vector2 endPosition, Color color)
  398. {
  399. if (guiWrapper.eventType != EventType.Repaint)
  400. return;
  401. Handles.color = color;
  402. float width = kEdgeWidth / Handles.matrix.m00;
  403. DrawingUtility.DrawSolidLine(width, startPosition, endPosition);
  404. }
  405. public void DoRepaint()
  406. {
  407. if(guiWrapper.eventType != EventType.Layout)
  408. return;
  409. var action = MeshEditorAction.None;
  410. if(IsActionActive(MeshEditorAction.CreateVertex))
  411. action = MeshEditorAction.CreateVertex;
  412. else if(IsActionActive(MeshEditorAction.CreateEdge))
  413. action = MeshEditorAction.CreateEdge;
  414. else if(IsActionActive(MeshEditorAction.SplitEdge))
  415. action = MeshEditorAction.SplitEdge;
  416. if(m_PreviousActiveAction != action)
  417. {
  418. m_PreviousActiveAction = action;
  419. guiWrapper.Repaint();
  420. }
  421. }
  422. public bool CanRepaint()
  423. {
  424. return guiWrapper.eventType == EventType.Repaint;
  425. }
  426. public bool CanLayout()
  427. {
  428. return guiWrapper.eventType == EventType.Layout;
  429. }
  430. }
  431. }