362 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			362 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using System.Collections.Generic; | ||
|  | using System.Linq; | ||
|  | using UnityEditor.U2D.Common; | ||
|  | using UnityEditor.U2D.Layout; | ||
|  | 
 | ||
|  | namespace UnityEditor.U2D.Animation | ||
|  | { | ||
|  |     internal class SpriteBoneInfluenceToolController | ||
|  |     { | ||
|  |         SkinningEvents m_Events; | ||
|  |         ISpriteBoneInfluenceToolModel m_Model; | ||
|  | 
 | ||
|  |         public SpriteBoneInfluenceToolController(ISpriteBoneInfluenceToolModel model, SkinningEvents events) | ||
|  |         { | ||
|  |             m_Events = events; | ||
|  |             m_Model = model; | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Activate() | ||
|  |         { | ||
|  |             m_Events.selectedSpriteChanged.AddListener(OnSpriteSelectionChanged); | ||
|  |             m_Events.boneSelectionChanged.AddListener(OnBoneSelectionChanged); | ||
|  |             m_Events.boneNameChanged.AddListener(OnBoneNameChanged); | ||
|  |             m_Events.skeletonTopologyChanged.AddListener(OnSkeletonTopologyChanged); | ||
|  |             m_Events.meshChanged.AddListener(OnMeshChanged); | ||
|  |             m_Events.skinningModeChanged.AddListener(OnSkinningModeChanged); | ||
|  | 
 | ||
|  |             ShowHideView(true); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Deactivate() | ||
|  |         { | ||
|  |             m_Events.selectedSpriteChanged.RemoveListener(OnSpriteSelectionChanged); | ||
|  |             m_Events.boneSelectionChanged.RemoveListener(OnBoneSelectionChanged); | ||
|  |             m_Events.boneNameChanged.RemoveListener(OnBoneNameChanged); | ||
|  |             m_Events.skeletonTopologyChanged.RemoveListener(OnSkeletonTopologyChanged); | ||
|  |             m_Events.meshChanged.RemoveListener(OnMeshChanged); | ||
|  |             m_Events.skinningModeChanged.RemoveListener(OnSkinningModeChanged); | ||
|  | 
 | ||
|  |             ShowHideView(false); | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnMeshChanged(MeshCache mesh) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnSpriteSelectionChanged(SpriteCache sprite) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 UpdateSelectedSpriteBoneInfluence(); | ||
|  |                 m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |                 SetViewHeaderText(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnBoneSelectionChanged() | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnBoneNameChanged(BoneCache bone) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnSkeletonTopologyChanged(SkeletonCache skeleton) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 UpdateSelectedSpriteBoneInfluence(); | ||
|  | 
 | ||
|  |                 m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void UpdateAddRemoveButtons() | ||
|  |         { | ||
|  |             m_Model.view.ToggleAddButton(ShouldEnableAddButton()); | ||
|  |             m_Model.view.ToggleRemoveButton(InCharacterMode()); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void OnViewCreated() | ||
|  |         { | ||
|  |             m_Model.view.onAddElement += AddSelectedBoneInfluenceToSprite; | ||
|  |             m_Model.view.onRemoveElement += RemoveSelectedBoneInfluenceFromSprite; | ||
|  |             m_Model.view.onReordered += OnReorderBoneInfluenceFromSprite; | ||
|  |             m_Model.view.onSelectionChanged += SelectedBonesFromList; | ||
|  | 
 | ||
|  |             ShowHideView(false); | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnSkinningModeChanged(SkinningMode skinningMode) | ||
|  |         { | ||
|  |             UpdateAddRemoveButtons(); | ||
|  |         } | ||
|  | 
 | ||
|  |         void AddSelectedBoneInfluenceToSprite() | ||
|  |         { | ||
|  |             SkeletonCache character = m_Model.characterSkeleton; | ||
|  | 
 | ||
|  |             if (character == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             CharacterPartCache characterPart = m_Model.GetSpriteCharacterPart(m_Model.selectedSprite); | ||
|  |             IEnumerable<BoneCache> selectedBones = m_Model.selectedBones; | ||
|  |             List<BoneCache> characterBones = characterPart.bones.ToList(); | ||
|  | 
 | ||
|  |             foreach (BoneCache bone in selectedBones) | ||
|  |             { | ||
|  |                 if (!characterBones.Contains(bone)) | ||
|  |                     characterBones.Add(bone as BoneCache); | ||
|  |             } | ||
|  | 
 | ||
|  |             using (m_Model.UndoScope(TextContent.addBoneInfluence)) | ||
|  |             { | ||
|  |                 characterPart.bones = characterBones.ToArray(); | ||
|  |                 m_Events.characterPartChanged.Invoke(characterPart); | ||
|  | 
 | ||
|  |                 UpdateSelectedSpriteBoneInfluence(); | ||
|  |                 m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void RemoveSelectedBoneInfluenceFromSprite() | ||
|  |         { | ||
|  |             SkeletonCache character = m_Model.characterSkeleton; | ||
|  | 
 | ||
|  |             if (character == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             CharacterPartCache characterPart = m_Model.GetSpriteCharacterPart(m_Model.selectedSprite); | ||
|  |             IEnumerable<BoneCache> selectedBones = m_Model.selectedBones; | ||
|  |             List<BoneCache> characterBones = characterPart.bones.ToList(); | ||
|  | 
 | ||
|  |             characterBones.RemoveAll(b => selectedBones.Contains(b)); | ||
|  | 
 | ||
|  |             using (m_Model.UndoScope(TextContent.removeBoneInfluence)) | ||
|  |             { | ||
|  |                 characterPart.bones = characterBones.ToArray(); | ||
|  |                 m_Events.characterPartChanged.Invoke(characterPart); | ||
|  | 
 | ||
|  |                 characterPart.sprite.SmoothFill(); | ||
|  |                 m_Events.meshChanged.Invoke(characterPart.sprite.GetMesh()); | ||
|  | 
 | ||
|  |                 UpdateSelectedSpriteBoneInfluence(); | ||
|  |                 m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnReorderBoneInfluenceFromSprite(IEnumerable<TransformCache> transformCache) | ||
|  |         { | ||
|  |             IEnumerable<BoneCache> boneCache = transformCache.Cast<BoneCache>(); | ||
|  | 
 | ||
|  |             SkeletonCache character = m_Model.characterSkeleton; | ||
|  | 
 | ||
|  |             if (character != null) | ||
|  |             { | ||
|  |                 CharacterPartCache characterPart = m_Model.GetSpriteCharacterPart(m_Model.selectedSprite); | ||
|  |                 using (m_Model.UndoScope(TextContent.reorderBoneInfluence)) | ||
|  |                 { | ||
|  |                     characterPart.bones = boneCache.ToArray(); | ||
|  |                     m_Events.characterPartChanged.Invoke(characterPart); | ||
|  | 
 | ||
|  |                     UpdateSelectedSpriteBoneInfluence(); | ||
|  |                     m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 using (m_Model.UndoScope(TextContent.reorderBoneInfluence)) | ||
|  |                 { | ||
|  |                     m_Model.selectedSprite.GetSkeleton().ReorderBones(boneCache); | ||
|  |                     m_Events.skeletonTopologyChanged.Invoke(m_Model.selectedSprite.GetSkeleton()); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void SelectedBonesFromList(IEnumerable<object> selectedBones) | ||
|  |         { | ||
|  |             using (m_Model.UndoScope(TextContent.boneSelection)) | ||
|  |             { | ||
|  |                 m_Model.selectedBones = selectedBones.Cast<BoneCache>(); | ||
|  |                 m_Events.boneSelectionChanged.Invoke(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private void ShowHideView(bool show) | ||
|  |         { | ||
|  |             m_Model.view.SetHiddenFromLayout(!show); | ||
|  |             if (show) | ||
|  |             { | ||
|  |                 UpdateSelectedSpriteBoneInfluence(); | ||
|  |                 m_Model.view.UpdateList(m_Model.selectionInfluencedBones); | ||
|  |                 m_Model.view.UpdateSelection(m_Model.selectedBones); | ||
|  |                 m_Model.view.listLabelText = TextContent.boneInfluences; | ||
|  |                 m_Model.view.SetTooltips(TextContent.addBoneInfluenceTooltip, TextContent.removeBoneInfluenceTooltip); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |                 SetViewHeaderText(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void SetViewHeaderText() | ||
|  |         { | ||
|  |             string headerText = m_Model.selectedSprite != null ? m_Model.selectedSprite.name : TextContent.noSpriteSelected; | ||
|  |             m_Model.view.headerText = headerText; | ||
|  |         } | ||
|  | 
 | ||
|  |         void UpdateSelectedSpriteBoneInfluence() | ||
|  |         { | ||
|  |             List<TransformCache> selectedSpriteInfluences = new List<TransformCache>(); | ||
|  |             SpriteCache selectedSprite = m_Model.selectedSprite; | ||
|  | 
 | ||
|  |             if (selectedSprite != null) | ||
|  |             { | ||
|  |                 if (m_Model.hasCharacter) | ||
|  |                 { | ||
|  |                     CharacterPartCache characterPart = m_Model.GetSpriteCharacterPart(selectedSprite); | ||
|  |                     selectedSpriteInfluences = characterPart.bones.Cast<TransformCache>().ToList(); | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     selectedSpriteInfluences = selectedSprite.GetSkeleton().bones.Cast<TransformCache>().ToList(); | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             m_Model.selectionInfluencedBones = selectedSpriteInfluences; | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool ShouldEnableAddButton() | ||
|  |         { | ||
|  |             if (InCharacterMode()) | ||
|  |             { | ||
|  |                 bool hasSelectedSprite = m_Model.selectedSprite != null; | ||
|  |                 IEnumerable<BoneCache> selectedBones = m_Model.selectedBones; | ||
|  |                 return hasSelectedSprite && selectedBones.FirstOrDefault(x => !m_Model.selectionInfluencedBones.Contains(x)) != null; | ||
|  |             } | ||
|  | 
 | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         private bool InCharacterMode() | ||
|  |         { | ||
|  |             return m_Model.hasCharacter && m_Model.skinningMode == SkinningMode.Character; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     internal interface ISpriteBoneInfluenceToolModel | ||
|  |     { | ||
|  |         IInfluenceWindow view { get; } | ||
|  |         IEnumerable<BoneCache> selectedBones { get; set; } | ||
|  |         List<TransformCache> selectionInfluencedBones { get; set; } | ||
|  |         SpriteCache selectedSprite { get; } | ||
|  |         bool hasCharacter { get; } | ||
|  |         SkinningMode skinningMode { get; } | ||
|  |         SkeletonCache characterSkeleton { get; } | ||
|  |         UndoScope UndoScope(string description); | ||
|  |         CharacterPartCache GetSpriteCharacterPart(SpriteCache sprite); | ||
|  |     } | ||
|  | 
 | ||
|  |     internal class SpriteBoneInfluenceTool : BaseTool, ISpriteBoneInfluenceToolModel | ||
|  |     { | ||
|  |         private SpriteBoneInfluenceToolController m_Controller; | ||
|  |         private MeshPreviewBehaviour m_MeshPreviewBehaviour = new MeshPreviewBehaviour(); | ||
|  |         private InfluenceWindow m_View; | ||
|  | 
 | ||
|  |         public SkeletonTool skeletonTool { set; private get; } | ||
|  |         public override IMeshPreviewBehaviour previewBehaviour => m_MeshPreviewBehaviour; | ||
|  | 
 | ||
|  |         internal override void OnCreate() | ||
|  |         { | ||
|  |             m_Controller = new SpriteBoneInfluenceToolController(this, skinningCache.events); | ||
|  |         } | ||
|  | 
 | ||
|  |         IInfluenceWindow ISpriteBoneInfluenceToolModel.view => m_View; | ||
|  | 
 | ||
|  |         IEnumerable<BoneCache> ISpriteBoneInfluenceToolModel.selectedBones | ||
|  |         { | ||
|  |             get => skinningCache.skeletonSelection.elements; | ||
|  |             set => skinningCache.skeletonSelection.elements = value.ToArray(); | ||
|  |         } | ||
|  | 
 | ||
|  |         List<TransformCache> ISpriteBoneInfluenceToolModel.selectionInfluencedBones { get; set; } | ||
|  | 
 | ||
|  |         SpriteCache ISpriteBoneInfluenceToolModel.selectedSprite => skinningCache.selectedSprite; | ||
|  |         bool ISpriteBoneInfluenceToolModel.hasCharacter => skinningCache.hasCharacter; | ||
|  |         SkinningMode ISpriteBoneInfluenceToolModel.skinningMode => skinningCache.mode; | ||
|  |         SkeletonCache ISpriteBoneInfluenceToolModel.characterSkeleton => skinningCache.character != null ? skinningCache.character.skeleton : null; | ||
|  | 
 | ||
|  |         UndoScope ISpriteBoneInfluenceToolModel.UndoScope(string description) | ||
|  |         { | ||
|  |             return skinningCache.UndoScope(description); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void OnActivate() | ||
|  |         { | ||
|  |             m_Controller.Activate(); | ||
|  |             if (skeletonTool != null) | ||
|  |                 skeletonTool.Activate(); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void OnDeactivate() | ||
|  |         { | ||
|  |             m_Controller.Deactivate(); | ||
|  |             if (skeletonTool != null) | ||
|  |                 skeletonTool.Deactivate(); | ||
|  |         } | ||
|  | 
 | ||
|  |         public override void Initialize(LayoutOverlay layout) | ||
|  |         { | ||
|  |             if (m_View == null) | ||
|  |             { | ||
|  |                 m_View = InfluenceWindow.CreateFromUxml(); | ||
|  |                 m_View.SetListReorderable(true); | ||
|  |                 m_View.SetAllowMultiselect(true); | ||
|  |                 m_View.LocalizeTextInChildren(); | ||
|  |                 m_Controller.OnViewCreated(); | ||
|  |             } | ||
|  | 
 | ||
|  |             layout.rightOverlay.Add(m_View); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void OnGUI() | ||
|  |         { | ||
|  |             m_MeshPreviewBehaviour.showWeightMap = true; | ||
|  |             m_MeshPreviewBehaviour.overlaySelected = true; | ||
|  |             m_MeshPreviewBehaviour.drawWireframe = true; | ||
|  | 
 | ||
|  |             skeletonTool.skeletonStyle = SkeletonStyles.WeightMap; | ||
|  |             skeletonTool.mode = SkeletonMode.EditPose; | ||
|  |             skeletonTool.editBindPose = false; | ||
|  |             skeletonTool.DoGUI(); | ||
|  |         } | ||
|  | 
 | ||
|  |         public CharacterPartCache GetSpriteCharacterPart(SpriteCache sprite) | ||
|  |         { | ||
|  |             return sprite.GetCharacterPart(); | ||
|  |         } | ||
|  |     } | ||
|  | } |