349 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			349 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using System; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Linq; | ||
|  | using UnityEditor.U2D.Layout; | ||
|  | 
 | ||
|  | namespace UnityEditor.U2D.Animation | ||
|  | { | ||
|  |     internal class BoneSpriteInfluenceToolController | ||
|  |     { | ||
|  |         SkinningEvents m_Events; | ||
|  |         IBoneSpriteInfluenceToolModel m_Model; | ||
|  | 
 | ||
|  |         public BoneSpriteInfluenceToolController(IBoneSpriteInfluenceToolModel 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 OnSpriteSelectionChanged(SpriteCache sprite) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 m_Model.view.UpdateSelection(new TransformCache[] { m_Model.selectedSprite }); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnBoneSelectionChanged() | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 UpdateSelectedBonesInfluencedSprites(); | ||
|  |                 m_Model.view.UpdateList(m_Model.influencedSprites); | ||
|  |                 m_Model.view.UpdateSelection(new TransformCache[] { m_Model.selectedSprite }); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |                 SetViewHeaderText(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnBoneNameChanged(BoneCache bone) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 SetViewHeaderText(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnSkeletonTopologyChanged(SkeletonCache skeleton) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 m_Model.view.UpdateList(m_Model.influencedSprites); | ||
|  |                 m_Model.view.UpdateSelection(new TransformCache[] { m_Model.selectedSprite }); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnMeshChanged(MeshCache mesh) | ||
|  |         { | ||
|  |             if (m_Model.view.visible) | ||
|  |             { | ||
|  |                 m_Model.view.UpdateList(m_Model.influencedSprites); | ||
|  |                 m_Model.view.UpdateSelection(new TransformCache[] { m_Model.selectedSprite }); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnSkinningModeChanged(SkinningMode skinningMode) | ||
|  |         { | ||
|  |             UpdateAddRemoveButtons(); | ||
|  |         } | ||
|  | 
 | ||
|  |         void ShowHideView(bool show) | ||
|  |         { | ||
|  |             m_Model.view.SetHiddenFromLayout(!show); | ||
|  |             if (show) | ||
|  |             { | ||
|  |                 UpdateSelectedBonesInfluencedSprites(); | ||
|  |                 m_Model.view.UpdateList(m_Model.influencedSprites); | ||
|  |                 m_Model.view.UpdateSelection(new TransformCache[] { m_Model.selectedSprite }); | ||
|  |                 m_Model.view.listLabelText = TextContent.influencedSprites; | ||
|  |                 m_Model.view.SetTooltips(TextContent.addSpriteInfluenceTooltip, TextContent.removeSpriteInfluenceTooltip); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |                 SetViewHeaderText(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void SetViewHeaderText() | ||
|  |         { | ||
|  |             string headerText = m_Model.selectedBone != null ? m_Model.selectedBone.name : TextContent.noBoneSelected; | ||
|  |             m_Model.view.headerText = headerText; | ||
|  |         } | ||
|  | 
 | ||
|  |         public void OnViewCreated() | ||
|  |         { | ||
|  |             m_Model.view.onAddElement += AddSelectedSpriteInfluenceToBone; | ||
|  |             m_Model.view.onRemoveElement += RemoveSelectedSpriteInfluenceFromBone; | ||
|  |             m_Model.view.onSelectionChanged += SelectSprite; | ||
|  | 
 | ||
|  |             ShowHideView(false); | ||
|  |         } | ||
|  | 
 | ||
|  |         void AddSelectedSpriteInfluenceToBone() | ||
|  |         { | ||
|  |             if (m_Model.selectedSprite == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             SkeletonCache character = m_Model.characterSkeleton; | ||
|  | 
 | ||
|  |             if (character == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             if (m_Model.influencedSprites.Contains(m_Model.selectedSprite)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             CharacterPartCache characterPart = m_Model.GetSpriteCharacterPart(m_Model.selectedSprite); | ||
|  |             List<BoneCache> characterBones = characterPart.bones.ToList(); | ||
|  |             BoneCache selectedBone = m_Model.selectedBone; | ||
|  |             characterBones.Add(selectedBone); | ||
|  | 
 | ||
|  |             using (m_Model.UndoScope(TextContent.addSpriteInfluence)) | ||
|  |             { | ||
|  |                 characterPart.bones = characterBones.ToArray(); | ||
|  |                 m_Events.characterPartChanged.Invoke(characterPart); | ||
|  | 
 | ||
|  |                 UpdateSelectedBonesInfluencedSprites(); | ||
|  |                 m_Model.view.UpdateList(m_Model.influencedSprites); | ||
|  |                 m_Model.view.UpdateSelection(new TransformCache[] { m_Model.selectedSprite }); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void RemoveSelectedSpriteInfluenceFromBone() | ||
|  |         { | ||
|  |             SkeletonCache character = m_Model.characterSkeleton; | ||
|  | 
 | ||
|  |             if (character == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             BoneCache selectedBone = m_Model.selectedBone; | ||
|  |             SpriteCache selectedSprite = m_Model.selectedSprite; | ||
|  | 
 | ||
|  |             using (m_Model.UndoScope(TextContent.removeSpriteInfluence)) | ||
|  |             { | ||
|  |                 CharacterPartCache characterPart = m_Model.GetSpriteCharacterPart(selectedSprite); | ||
|  |                 List<BoneCache> characterBones = characterPart.bones.ToList(); | ||
|  |                 characterBones.Remove(selectedBone); | ||
|  | 
 | ||
|  |                 characterPart.bones = characterBones.ToArray(); | ||
|  |                 m_Events.characterPartChanged.Invoke(characterPart); | ||
|  | 
 | ||
|  |                 selectedSprite.SmoothFill(); | ||
|  | 
 | ||
|  |                 UpdateSelectedBonesInfluencedSprites(); | ||
|  |                 m_Model.view.UpdateList(m_Model.influencedSprites); | ||
|  |                 m_Model.view.UpdateSelection(new TransformCache[] { m_Model.selectedSprite }); | ||
|  |                 UpdateAddRemoveButtons(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void SelectSprite(IEnumerable<object> selectedSprite) | ||
|  |         { | ||
|  |             using (m_Model.UndoScope(TextContent.spriteSelection)) | ||
|  |             { | ||
|  |                 object firstSelected = selectedSprite.FirstOrDefault(); | ||
|  |                 m_Model.selectedSprite = (SpriteCache)firstSelected; | ||
|  |                 m_Events.selectedSpriteChanged.Invoke(m_Model.selectedSprite); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void UpdateSelectedBonesInfluencedSprites() | ||
|  |         { | ||
|  |             BoneCache selectedBone = m_Model.selectedBone; | ||
|  | 
 | ||
|  |             if (selectedBone != null) | ||
|  |             { | ||
|  |                 if (m_Model.hasCharacter) | ||
|  |                 { | ||
|  |                     List<TransformCache> spriteList = new List<TransformCache>(); | ||
|  | 
 | ||
|  |                     foreach (CharacterPartCache characterPartCache in selectedBone.skinningCache.character.parts) | ||
|  |                     { | ||
|  |                         if (characterPartCache.bones.Contains(selectedBone)) | ||
|  |                             spriteList.Add(characterPartCache.sprite); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     m_Model.influencedSprites = spriteList; | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     List<TransformCache> spriteList = new List<TransformCache>(); | ||
|  |                     SpriteCache[] sprites = selectedBone.skinningCache.GetSprites(); | ||
|  |                     foreach (SpriteCache sprite in sprites) | ||
|  |                     { | ||
|  |                         if (sprite.GetSkeleton().bones.Contains(selectedBone)) | ||
|  |                             spriteList.Add(sprite); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     m_Model.influencedSprites = spriteList; | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 m_Model.influencedSprites = new List<TransformCache>(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool ShouldEnableAddButton() | ||
|  |         { | ||
|  |             if (IsCharacterMode()) | ||
|  |             { | ||
|  |                 bool hasSelectedBone = m_Model.selectedBone != null; | ||
|  |                 SpriteCache selectedSprite = m_Model.selectedSprite; | ||
|  |                 bool hasSelectedSprite = selectedSprite != null; | ||
|  |                 return hasSelectedBone && hasSelectedSprite && !m_Model.influencedSprites.Contains(selectedSprite); | ||
|  |             } | ||
|  | 
 | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         void UpdateAddRemoveButtons() | ||
|  |         { | ||
|  |             m_Model.view.ToggleAddButton(ShouldEnableAddButton()); | ||
|  |             m_Model.view.ToggleRemoveButton(IsCharacterMode()); | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool IsCharacterMode() | ||
|  |         { | ||
|  |             return m_Model.hasCharacter && m_Model.skinningMode == SkinningMode.Character; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     interface IBoneSpriteInfluenceToolModel | ||
|  |     { | ||
|  |         IInfluenceWindow view { get; } | ||
|  |         BoneCache selectedBone { get; } | ||
|  |         SpriteCache selectedSprite { get; set; } | ||
|  |         List<TransformCache> influencedSprites { get; set; } | ||
|  |         bool hasCharacter { get; } | ||
|  |         SkinningMode skinningMode { get; } | ||
|  |         SkeletonCache characterSkeleton { get; } | ||
|  |         UndoScope UndoScope(string description); | ||
|  |         CharacterPartCache GetSpriteCharacterPart(SpriteCache sprite); | ||
|  |     } | ||
|  | 
 | ||
|  |     class BoneSpriteInfluenceTool : BaseTool, IBoneSpriteInfluenceToolModel | ||
|  |     { | ||
|  |         BoneSpriteInfluenceToolController m_Controller; | ||
|  |         MeshPreviewBehaviour m_MeshPreviewBehaviour = new MeshPreviewBehaviour(); | ||
|  |         InfluenceWindow m_View; | ||
|  | 
 | ||
|  |         public SkeletonTool skeletonTool { get; set; } | ||
|  | 
 | ||
|  |         public override IMeshPreviewBehaviour previewBehaviour => m_MeshPreviewBehaviour; | ||
|  | 
 | ||
|  |         internal override void OnCreate() | ||
|  |         { | ||
|  |             m_Controller = new BoneSpriteInfluenceToolController(this, skinningCache.events); | ||
|  |         } | ||
|  | 
 | ||
|  |         IInfluenceWindow IBoneSpriteInfluenceToolModel.view => m_View; | ||
|  | 
 | ||
|  |         BoneCache IBoneSpriteInfluenceToolModel.selectedBone => skinningCache.skeletonSelection.elements.FirstOrDefault(); | ||
|  | 
 | ||
|  |         SpriteCache IBoneSpriteInfluenceToolModel.selectedSprite | ||
|  |         { | ||
|  |             get => skinningCache.selectedSprite; | ||
|  |             set => skinningCache.selectedSprite = value; | ||
|  |         } | ||
|  | 
 | ||
|  |         List<TransformCache> IBoneSpriteInfluenceToolModel.influencedSprites { get; set; } | ||
|  |         bool IBoneSpriteInfluenceToolModel.hasCharacter => skinningCache.hasCharacter; | ||
|  |         SkinningMode IBoneSpriteInfluenceToolModel.skinningMode => skinningCache.mode; | ||
|  |         SkeletonCache IBoneSpriteInfluenceToolModel.characterSkeleton => skinningCache.character != null ? skinningCache.character.skeleton : null; | ||
|  | 
 | ||
|  |         UndoScope IBoneSpriteInfluenceToolModel.UndoScope(string description) | ||
|  |         { | ||
|  |             return skinningCache.UndoScope(description); | ||
|  |         } | ||
|  | 
 | ||
|  |         public CharacterPartCache GetSpriteCharacterPart(SpriteCache sprite) | ||
|  |         { | ||
|  |             return sprite.GetCharacterPart(); | ||
|  |         } | ||
|  | 
 | ||
|  |         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(false); | ||
|  |                 m_View.SetAllowMultiselect(false); | ||
|  |                 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(); | ||
|  |         } | ||
|  |     } | ||
|  | } |