357 lines
13 KiB
C#
357 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
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()
|
|
{
|
|
var character = m_Model.characterSkeleton;
|
|
|
|
if (character == null)
|
|
return;
|
|
|
|
var characterPart = m_Model.GetSpriteCharacterPart(m_Model.selectedSprite);
|
|
var selectedBones = m_Model.selectedBones;
|
|
var characterBones = characterPart.bones.ToList();
|
|
|
|
foreach (var 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()
|
|
{
|
|
var character = m_Model.characterSkeleton;
|
|
|
|
if (character == null)
|
|
return;
|
|
|
|
var characterPart = m_Model.GetSpriteCharacterPart(m_Model.selectedSprite);
|
|
var selectedBones = m_Model.selectedBones;
|
|
var 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)
|
|
{
|
|
var boneCache = transformCache.Cast<BoneCache>();
|
|
|
|
var character = m_Model.characterSkeleton;
|
|
|
|
if (character != null)
|
|
{
|
|
var 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()
|
|
{
|
|
var headerText = m_Model.selectedSprite != null ? m_Model.selectedSprite.name : TextContent.noSpriteSelected;
|
|
m_Model.view.headerText = headerText;
|
|
}
|
|
|
|
void UpdateSelectedSpriteBoneInfluence()
|
|
{
|
|
var selectedSpriteInfluences = new List<TransformCache>();
|
|
var selectedSprite = m_Model.selectedSprite;
|
|
|
|
if (selectedSprite != null)
|
|
{
|
|
if (m_Model.hasCharacter)
|
|
{
|
|
var 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())
|
|
{
|
|
var hasSelectedSprite = m_Model.selectedSprite != null;
|
|
var 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();
|
|
}
|
|
}
|
|
}
|