SkinningModule.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. using UnityEngine;
  2. using System;
  3. using System.Linq;
  4. using System.Collections.Generic;
  5. using UnityEditor.U2D.Sprites;
  6. namespace UnityEditor.U2D.Animation
  7. {
  8. [RequireSpriteDataProvider(typeof(ISpriteMeshDataProvider), typeof(ISpriteBoneDataProvider))]
  9. internal partial class SkinningModule : SpriteEditorModuleBase
  10. {
  11. private static class Styles
  12. {
  13. public static string moduleName = L10n.Tr("Skinning Editor");
  14. }
  15. private SkinningCache m_SkinningCache;
  16. private int m_PrevNearestControl = -1;
  17. private SpriteOutlineRenderer m_SpriteOutlineRenderer;
  18. private MeshPreviewTool m_MeshPreviewTool;
  19. private SkinningMode m_PreviousSkinningMode;
  20. private SpriteBoneInfluenceTool m_CharacterSpriteTool;
  21. private HorizontalToggleTools m_HorizontalToggleTools;
  22. private AnimationAnalytics m_Analytics;
  23. private ModuleToolGroup m_ModuleToolGroup;
  24. IMeshPreviewBehaviour m_MeshPreviewBehaviourOverride = null;
  25. bool m_CollapseToolbar;
  26. internal SkinningCache skinningCache
  27. {
  28. get { return m_SkinningCache; }
  29. }
  30. private BaseTool currentTool
  31. {
  32. get { return skinningCache.selectedTool; }
  33. set { skinningCache.selectedTool = value; }
  34. }
  35. public override string moduleName
  36. {
  37. get { return Styles.moduleName; }
  38. }
  39. public override void OnModuleActivate()
  40. {
  41. m_SkinningCache = Cache.Create<SkinningCache>();
  42. AddMainUI(spriteEditor.GetMainVisualContainer());
  43. using (skinningCache.DisableUndoScope())
  44. {
  45. skinningCache.Create(spriteEditor, SkinningCachePersistentState.instance);
  46. skinningCache.CreateToolCache(spriteEditor, m_LayoutOverlay);
  47. m_CharacterSpriteTool = skinningCache.CreateTool<SpriteBoneInfluenceTool>();
  48. m_CharacterSpriteTool.Initialize(m_LayoutOverlay);
  49. m_MeshPreviewTool = skinningCache.CreateTool<MeshPreviewTool>();
  50. SetupModuleToolGroup();
  51. m_MeshPreviewTool.Activate();
  52. m_SpriteOutlineRenderer = new SpriteOutlineRenderer(skinningCache.events);
  53. spriteEditor.enableMouseMoveEvent = true;
  54. Undo.undoRedoPerformed += UndoRedoPerformed;
  55. skinningCache.events.skeletonTopologyChanged.AddListener(SkeletonTopologyChanged);
  56. skinningCache.events.skeletonPreviewPoseChanged.AddListener(SkeletonPreviewPoseChanged);
  57. skinningCache.events.skeletonBindPoseChanged.AddListener(SkeletonBindPoseChanged);
  58. skinningCache.events.characterPartChanged.AddListener(CharacterPartChanged);
  59. skinningCache.events.skinningModeChanged.AddListener(OnViewModeChanged);
  60. skinningCache.events.meshChanged.AddListener(OnMeshChanged);
  61. skinningCache.events.boneNameChanged.AddListener(OnBoneNameChanged);
  62. skinningCache.events.boneDepthChanged.AddListener(OnBoneDepthChanged);
  63. skinningCache.events.spriteLibraryChanged.AddListener(OnSpriteLibraryChanged);
  64. skinningCache.events.meshPreviewBehaviourChange.AddListener(OnMeshPreviewBehaviourChange);
  65. skinningCache.RestoreFromPersistentState();
  66. ActivateTool(skinningCache.selectedTool);
  67. skinningCache.RestoreToolStateFromPersistentState();
  68. // Set state for Switch Mode tool
  69. m_PreviousSkinningMode = skinningCache.mode;
  70. if (skinningCache.mode == SkinningMode.Character)
  71. {
  72. skinningCache.GetTool(Tools.SwitchMode).Deactivate();
  73. }
  74. else
  75. {
  76. skinningCache.GetTool(Tools.SwitchMode).Activate();
  77. }
  78. SetupSpriteEditor(true);
  79. m_HorizontalToggleTools = new HorizontalToggleTools(skinningCache)
  80. {
  81. onActivateTool = (b) =>
  82. {
  83. using (skinningCache.UndoScope(TextContent.setTool))
  84. {
  85. ActivateTool(b);
  86. }
  87. }
  88. };
  89. var ai = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>() as AssetImporter;
  90. m_Analytics = new AnimationAnalytics(new UnityAnalyticsStorage(),
  91. skinningCache.events,
  92. new SkinningModuleAnalyticsModel(skinningCache),
  93. ai == null ? -1 : ai.GetInstanceID());
  94. UpdateCollapseToolbar();
  95. }
  96. }
  97. public override void OnModuleDeactivate()
  98. {
  99. if (m_SpriteOutlineRenderer != null)
  100. m_SpriteOutlineRenderer.Dispose();
  101. spriteEditor.enableMouseMoveEvent = false;
  102. Undo.undoRedoPerformed -= UndoRedoPerformed;
  103. skinningCache.events.skeletonTopologyChanged.RemoveListener(SkeletonTopologyChanged);
  104. skinningCache.events.skeletonPreviewPoseChanged.RemoveListener(SkeletonPreviewPoseChanged);
  105. skinningCache.events.skeletonBindPoseChanged.RemoveListener(SkeletonBindPoseChanged);
  106. skinningCache.events.characterPartChanged.RemoveListener(CharacterPartChanged);
  107. skinningCache.events.skinningModeChanged.RemoveListener(OnViewModeChanged);
  108. skinningCache.events.meshChanged.RemoveListener(OnMeshChanged);
  109. skinningCache.events.boneNameChanged.RemoveListener(OnBoneNameChanged);
  110. skinningCache.events.boneDepthChanged.RemoveListener(OnBoneDepthChanged);
  111. skinningCache.events.spriteLibraryChanged.RemoveListener(OnSpriteLibraryChanged);
  112. skinningCache.events.meshPreviewBehaviourChange.RemoveListener(OnMeshPreviewBehaviourChange);
  113. RemoveMainUI(spriteEditor.GetMainVisualContainer());
  114. RestoreSpriteEditor();
  115. m_Analytics.Dispose();
  116. m_Analytics = null;
  117. Cache.Destroy(m_SkinningCache);
  118. }
  119. private void UpdateCollapseToolbar()
  120. {
  121. m_CollapseToolbar = SkinningModuleSettings.compactToolBar;
  122. m_WeightToolbar.CollapseToolBar(m_CollapseToolbar);
  123. m_MeshToolbar.CollapseToolBar(m_CollapseToolbar);
  124. m_BoneToolbar.CollapseToolBar(m_CollapseToolbar);
  125. m_LayoutOverlay.verticalToolbar.Collapse(m_CollapseToolbar);
  126. m_HorizontalToggleTools.collapseToolbar = m_CollapseToolbar;
  127. }
  128. private void OnBoneNameChanged(BoneCache bone)
  129. {
  130. var character = skinningCache.character;
  131. if (character != null && character.skeleton == bone.skeleton)
  132. skinningCache.SyncSpriteSheetSkeletons();
  133. DataModified();
  134. }
  135. private void OnBoneDepthChanged(BoneCache bone)
  136. {
  137. var sprites = skinningCache.GetSprites();
  138. var controller = new SpriteMeshDataController();
  139. foreach (var sprite in sprites)
  140. {
  141. var mesh = sprite.GetMesh();
  142. if (mesh.ContainsBone(bone))
  143. {
  144. controller.spriteMeshData = mesh;
  145. controller.SortTrianglesByDepth();
  146. skinningCache.events.meshChanged.Invoke(mesh);
  147. }
  148. }
  149. DataModified();
  150. }
  151. private void OnMeshChanged(MeshCache mesh)
  152. {
  153. DataModified();
  154. }
  155. private void DataModified()
  156. {
  157. spriteEditor.SetDataModified();
  158. }
  159. private void OnViewModeChanged(SkinningMode mode)
  160. {
  161. SetupSpriteEditor();
  162. }
  163. private void SetupSpriteEditor(bool setPreviewTexture = false)
  164. {
  165. var textureProvider = spriteEditor.GetDataProvider<ITextureDataProvider>();
  166. if (textureProvider == null)
  167. return;
  168. var emptyTexture = new Texture2D(1, 1, TextureFormat.RGBAHalf, false, true);
  169. emptyTexture.hideFlags = HideFlags.HideAndDontSave;
  170. emptyTexture.SetPixel(1, 1, new Color(0, 0, 0, 0));
  171. emptyTexture.Apply();
  172. int width = 0, height = 0;
  173. if (skinningCache.mode == SkinningMode.SpriteSheet)
  174. {
  175. textureProvider.GetTextureActualWidthAndHeight(out width, out height);
  176. }
  177. else
  178. {
  179. width = skinningCache.character.dimension.x;
  180. height = skinningCache.character.dimension.y;
  181. }
  182. if (m_PreviousSkinningMode != skinningCache.mode || setPreviewTexture)
  183. {
  184. spriteEditor.SetPreviewTexture(emptyTexture, width, height);
  185. if (m_PreviousSkinningMode != skinningCache.mode)
  186. {
  187. m_PreviousSkinningMode = skinningCache.mode;
  188. spriteEditor.ResetZoomAndScroll();
  189. }
  190. }
  191. spriteEditor.spriteRects = new List<SpriteRect>();
  192. }
  193. private void RestoreSpriteEditor()
  194. {
  195. var textureProvider = spriteEditor.GetDataProvider<ITextureDataProvider>();
  196. if (textureProvider != null)
  197. {
  198. int width, height;
  199. textureProvider.GetTextureActualWidthAndHeight(out width, out height);
  200. var texture = textureProvider.previewTexture;
  201. spriteEditor.SetPreviewTexture(texture, width, height);
  202. }
  203. var spriteRectProvider = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
  204. if (spriteRectProvider != null)
  205. spriteEditor.spriteRects = new List<SpriteRect>(spriteRectProvider.GetSpriteRects());
  206. }
  207. public override bool CanBeActivated()
  208. {
  209. var dataProvider = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
  210. return dataProvider == null ? false : dataProvider.spriteImportMode != SpriteImportMode.None;
  211. }
  212. public override void DoPostGUI()
  213. {
  214. if (!spriteEditor.windowDimension.Contains(Event.current.mousePosition))
  215. HandleUtility.nearestControl = 0;
  216. if (Event.current.type == EventType.Layout && m_PrevNearestControl != HandleUtility.nearestControl)
  217. {
  218. m_PrevNearestControl = HandleUtility.nearestControl;
  219. spriteEditor.RequestRepaint();
  220. }
  221. skinningCache.EndUndoOperation();
  222. }
  223. public override void DoMainGUI()
  224. {
  225. Debug.Assert(currentTool != null);
  226. DoViewGUI();
  227. if (!spriteEditor.editingDisabled)
  228. skinningCache.selectionTool.DoGUI();
  229. m_MeshPreviewTool.previewBehaviourOverride = m_MeshPreviewBehaviourOverride != null ? m_MeshPreviewBehaviourOverride : currentTool.previewBehaviour;
  230. m_MeshPreviewTool.DoGUI();
  231. m_MeshPreviewTool.DrawOverlay();
  232. m_SpriteOutlineRenderer.RenderSpriteOutline(spriteEditor, skinningCache.selectedSprite);
  233. m_MeshPreviewTool.OverlayWireframe();
  234. if (!spriteEditor.editingDisabled)
  235. {
  236. currentTool.DoGUI();
  237. DoCopyPasteKeyboardEventHandling();
  238. }
  239. DrawRectGizmos();
  240. if (SkinningModuleSettings.compactToolBar != m_CollapseToolbar)
  241. UpdateCollapseToolbar();
  242. }
  243. public override void DoToolbarGUI(Rect drawArea)
  244. {
  245. m_HorizontalToggleTools.DoGUI(drawArea, currentTool, spriteEditor.editingDisabled);
  246. }
  247. void DoCopyPasteKeyboardEventHandling()
  248. {
  249. var evt = Event.current;
  250. if (evt.type == EventType.ValidateCommand)
  251. {
  252. if (evt.commandName == "Copy" || evt.commandName == "Paste")
  253. evt.Use();
  254. return;
  255. }
  256. if (evt.type == EventType.ExecuteCommand)
  257. {
  258. var copyTool = skinningCache.GetTool(Tools.CopyPaste) as CopyTool;
  259. if (copyTool != null && evt.commandName == "Copy")
  260. {
  261. copyTool.OnCopyActivated();
  262. evt.Use();
  263. }
  264. else if (copyTool != null && evt.commandName == "Paste")
  265. {
  266. copyTool.OnPasteActivated(true, true, false, false);
  267. evt.Use();
  268. }
  269. }
  270. }
  271. private void DrawRectGizmos()
  272. {
  273. if (Event.current.type == EventType.Repaint)
  274. {
  275. var selectedSprite = skinningCache.selectedSprite;
  276. var sprites = skinningCache.GetSprites();
  277. var unselectedRectColor = new Color(1f, 1f, 1f, 0.5f);
  278. foreach (var sprite in sprites)
  279. {
  280. var skeleton = skinningCache.GetEffectiveSkeleton(sprite);
  281. Debug.Assert(skeleton != null);
  282. if (skeleton.isPosePreview)
  283. continue;
  284. var color = unselectedRectColor;
  285. if (sprite == selectedSprite)
  286. color = DrawingUtility.kSpriteBorderColor;
  287. if (skinningCache.mode == SkinningMode.Character
  288. && sprite != selectedSprite)
  289. continue;
  290. var matrix = sprite.GetLocalToWorldMatrixFromMode();
  291. var rect = new Rect(matrix.MultiplyPoint3x4(Vector3.zero), sprite.textureRect.size);
  292. DrawingUtility.BeginLines(color);
  293. DrawingUtility.DrawBox(rect);
  294. DrawingUtility.EndLines();
  295. }
  296. }
  297. }
  298. private void UndoRedoPerformed()
  299. {
  300. using (new DisableUndoScope(skinningCache))
  301. {
  302. UpdateToggleState();
  303. skinningCache.UndoRedoPerformed();
  304. SetupSpriteEditor();
  305. }
  306. }
  307. #region CharacterConsistency
  308. //TODO: Bring this to a better place, maybe CharacterController
  309. private void SkeletonPreviewPoseChanged(SkeletonCache skeleton)
  310. {
  311. var character = skinningCache.character;
  312. if (character != null && character.skeleton == skeleton)
  313. skinningCache.SyncSpriteSheetSkeletons();
  314. }
  315. private void SkeletonBindPoseChanged(SkeletonCache skeleton)
  316. {
  317. var character = skinningCache.character;
  318. if (character != null && character.skeleton == skeleton)
  319. skinningCache.SyncSpriteSheetSkeletons();
  320. DataModified();
  321. }
  322. private void SkeletonTopologyChanged(SkeletonCache skeleton)
  323. {
  324. var character = skinningCache.character;
  325. if (character == null)
  326. {
  327. var sprite = FindSpriteFromSkeleton(skeleton);
  328. Debug.Assert(sprite != null);
  329. sprite.UpdateMesh(skeleton.bones);
  330. DataModified();
  331. }
  332. else if (character.skeleton == skeleton)
  333. {
  334. skinningCache.CreateSpriteSheetSkeletons();
  335. DataModified();
  336. }
  337. }
  338. private void CharacterPartChanged(CharacterPartCache characterPart)
  339. {
  340. var character = skinningCache.character;
  341. Debug.Assert(character != null);
  342. using (new DefaultPoseScope(character.skeleton))
  343. {
  344. skinningCache.CreateSpriteSheetSkeleton(characterPart);
  345. DataModified();
  346. }
  347. if (skinningCache.mode == SkinningMode.Character)
  348. characterPart.SyncSpriteSheetSkeleton();
  349. }
  350. private SpriteCache FindSpriteFromSkeleton(SkeletonCache skeleton)
  351. {
  352. var sprites = skinningCache.GetSprites();
  353. return sprites.FirstOrDefault(sprite => sprite.GetSkeleton() == skeleton);
  354. }
  355. #endregion
  356. public override bool ApplyRevert(bool apply)
  357. {
  358. if (apply)
  359. {
  360. m_Analytics.FlushEvent();
  361. skinningCache.applyingChanges = true;
  362. skinningCache.RestoreBindPose();
  363. ApplyBone();
  364. ApplyMesh();
  365. ApplyCharacter();
  366. skinningCache.applyingChanges = false;
  367. DoApplyAnalytics();
  368. }
  369. else
  370. skinningCache.Revert();
  371. return true;
  372. }
  373. private void DoApplyAnalytics()
  374. {
  375. var sprites = skinningCache.GetSprites();
  376. var spriteBoneCount = sprites.Select(s => s.GetSkeleton().BoneCount).ToArray();
  377. BoneCache[] bones = null;
  378. if (skinningCache.hasCharacter)
  379. bones = skinningCache.character.skeleton.bones;
  380. else
  381. bones = sprites.SelectMany(s => s.GetSkeleton().bones).ToArray();
  382. m_Analytics.SendApplyEvent(sprites.Length, spriteBoneCount, bones);
  383. }
  384. private void ApplyBone()
  385. {
  386. var boneDataProvider = spriteEditor.GetDataProvider<ISpriteBoneDataProvider>();
  387. if (boneDataProvider != null)
  388. {
  389. var sprites = skinningCache.GetSprites();
  390. foreach (var sprite in sprites)
  391. {
  392. var bones = sprite.GetSkeleton().bones;
  393. boneDataProvider.SetBones(new GUID(sprite.id), bones.ToSpriteBone(sprite.localToWorldMatrix).ToList());
  394. }
  395. }
  396. }
  397. private void ApplyMesh()
  398. {
  399. var meshDataProvider = spriteEditor.GetDataProvider<ISpriteMeshDataProvider>();
  400. if (meshDataProvider != null)
  401. {
  402. var sprites = skinningCache.GetSprites();
  403. foreach (var sprite in sprites)
  404. {
  405. var mesh = sprite.GetMesh();
  406. var guid = new GUID(sprite.id);
  407. meshDataProvider.SetVertices(guid, mesh.vertices.Select(x =>
  408. new Vertex2DMetaData()
  409. {
  410. boneWeight = x.editableBoneWeight.ToBoneWeight(false),
  411. position = x.position
  412. }
  413. ).ToArray());
  414. meshDataProvider.SetIndices(guid, mesh.indices.ToArray());
  415. meshDataProvider.SetEdges(guid, mesh.edges.Select(x => new Vector2Int(x.index1, x.index2)).ToArray());
  416. }
  417. }
  418. }
  419. private void ApplyCharacter()
  420. {
  421. var characterDataProvider = spriteEditor.GetDataProvider<ICharacterDataProvider>();
  422. var character = skinningCache.character;
  423. if (characterDataProvider != null && character != null)
  424. {
  425. var data = new CharacterData();
  426. var characterBones = character.skeleton.bones;
  427. data.bones = characterBones.ToSpriteBone(Matrix4x4.identity);
  428. var parts = character.parts;
  429. data.parts = parts.Select(x =>
  430. new CharacterPart()
  431. {
  432. spriteId = x.sprite.id,
  433. spritePosition = new RectInt((int)x.position.x, (int)x.position.y, (int)x.sprite.textureRect.width, (int)x.sprite.textureRect.height),
  434. bones = x.bones.Select(bone => Array.IndexOf(characterBones, bone)).ToArray()
  435. }
  436. ).ToArray();
  437. characterDataProvider.SetCharacterData(data);
  438. }
  439. var spriteLibDataProvider = spriteEditor.GetDataProvider<ISpriteLibDataProvider>();
  440. if (spriteLibDataProvider != null)
  441. {
  442. spriteLibDataProvider.SetSpriteCategoryList(skinningCache.spriteCategoryList.ToSpriteLibrary());
  443. }
  444. }
  445. void OnSpriteLibraryChanged()
  446. {
  447. DataModified();
  448. }
  449. void OnMeshPreviewBehaviourChange(IMeshPreviewBehaviour meshPreviewBehaviour)
  450. {
  451. m_MeshPreviewBehaviourOverride = meshPreviewBehaviour;
  452. }
  453. private void SetupModuleToolGroup()
  454. {
  455. m_ModuleToolGroup = new ModuleToolGroup();
  456. m_ModuleToolGroup.AddToolToGroup(0, skinningCache.GetTool(Tools.Visibility), null);
  457. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.EditGeometry), () => currentTool = skinningCache.GetTool(Tools.EditGeometry));
  458. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.CreateVertex), () => currentTool = skinningCache.GetTool(Tools.CreateVertex));
  459. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.CreateEdge), () => currentTool = skinningCache.GetTool(Tools.CreateEdge));
  460. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.SplitEdge), () => currentTool = skinningCache.GetTool(Tools.SplitEdge));
  461. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.GenerateGeometry), () => currentTool = skinningCache.GetTool(Tools.GenerateGeometry));
  462. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.EditPose), () => currentTool = skinningCache.GetTool(Tools.EditPose));
  463. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.EditJoints), () => currentTool = skinningCache.GetTool(Tools.EditJoints));
  464. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.CreateBone), () => currentTool = skinningCache.GetTool(Tools.CreateBone));
  465. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.SplitBone), () => currentTool = skinningCache.GetTool(Tools.SplitBone));
  466. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.WeightSlider), () => currentTool = skinningCache.GetTool(Tools.WeightSlider));
  467. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.WeightBrush), () => currentTool = skinningCache.GetTool(Tools.WeightBrush));
  468. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.GenerateWeights), () => currentTool = skinningCache.GetTool(Tools.GenerateWeights));
  469. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.BoneInfluence), () => currentTool = skinningCache.GetTool(Tools.BoneInfluence));
  470. m_ModuleToolGroup.AddToolToGroup(1, skinningCache.GetTool(Tools.CopyPaste), () => currentTool = skinningCache.GetTool(Tools.CopyPaste));
  471. }
  472. }
  473. }