123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644 |
- using System;
- using System.Collections.Generic;
- using System.Text.RegularExpressions;
- using UnityEngine;
- namespace UnityEditor.U2D.Animation
- {
- [Serializable]
- internal class SkeletonController
- {
- private static readonly string k_DefaultRootName = "root";
- private static readonly string k_DefaultBoneName = "bone";
- private static Regex s_Regex = new Regex(@"\w+_\d+$", RegexOptions.IgnoreCase);
- private SkeletonCache m_Skeleton;
- [SerializeField]
- private Vector3 m_CreateBoneStartPosition;
- [SerializeField]
- private BoneCache m_PrevCreatedBone;
- private bool m_Moved = false;
- private ISkeletonStyle style
- {
- get
- {
- if (styleOverride != null)
- return styleOverride;
- return SkeletonStyles.Default;
- }
- }
- private SkinningCache skinningCache
- {
- get { return m_Skeleton.skinningCache; }
- }
- private BoneCache selectedBone
- {
- get { return selection.activeElement.ToSpriteSheetIfNeeded(); }
- set { selection.activeElement = value.ToCharacterIfNeeded(); }
- }
- private BoneCache[] selectedBones
- {
- get { return selection.elements.ToSpriteSheetIfNeeded(); }
- set { selection.elements = value.ToCharacterIfNeeded(); }
- }
- private BoneCache rootBone
- {
- get { return selection.root.ToSpriteSheetIfNeeded(); }
- }
- private BoneCache[] rootBones
- {
- get { return selection.roots.ToSpriteSheetIfNeeded(); }
- }
- public ISkeletonView view { get; set; }
- public ISkeletonStyle styleOverride { get; set; }
- public IBoneSelection selection { get; set; }
- public bool editBindPose { get; set; }
- public SkeletonCache skeleton
- {
- get { return m_Skeleton; }
- set { SetSkeleton(value); }
- }
- public BoneCache hoveredBone
- {
- get { return GetBone(view.hoveredBoneID); }
- }
- public BoneCache hoveredTail
- {
- get { return GetBone(view.hoveredTailID); }
- }
- public BoneCache hoveredBody
- {
- get { return GetBone(view.hoveredBodyID); }
- }
- public BoneCache hoveredJoint
- {
- get { return GetBone(view.hoveredJointID); }
- }
- public BoneCache hotBone
- {
- get { return GetBone(view.hotBoneID); }
- }
- private BoneCache GetBone(int instanceID)
- {
- return BaseObject.InstanceIDToObject(instanceID) as BoneCache;
- }
- private void SetSkeleton(SkeletonCache newSkeleton)
- {
- if (skeleton != newSkeleton)
- {
- m_Skeleton = newSkeleton;
- Reset();
- }
- }
- public void Reset()
- {
- view.DoCancelMultistepAction(true);
- }
- public void OnGUI()
- {
- if (skeleton == null)
- return;
- view.BeginLayout();
- if (view.CanLayout())
- LayoutBones();
- view.EndLayout();
- HandleSelectBone();
- HandleRotateBone();
- HandleMoveBone();
- HandleFreeMoveBone();
- HandleMoveJoint();
- HandleMoveEndPosition();
- HandleChangeLength();
- HandleCreateBone();
- HandleSplitBone();
- HandleRemoveBone();
- HandleCancelMultiStepAction();
- DrawSkeleton();
- DrawSplitBonePreview();
- DrawCreateBonePreview();
- DrawCursors();
- }
- private void LayoutBones()
- {
- for (var i = 0; i < skeleton.BoneCount; ++i)
- {
- var bone = skeleton.GetBone(i);
- if (bone.isVisible && bone != hotBone)
- view.LayoutBone(bone.GetInstanceID(), bone.position, bone.endPosition, bone.forward, bone.up, bone.right, bone.chainedChild == null);
- }
- }
- private void HandleSelectBone()
- {
- int instanceID;
- bool additive;
- if (view.DoSelectBone(out instanceID, out additive))
- {
- var bone = GetBone(instanceID).ToCharacterIfNeeded();
- using (skinningCache.UndoScope(TextContent.boneSelection, true))
- {
- if (!additive)
- {
- if (!selection.Contains(bone))
- selectedBone = bone;
- }
- else
- selection.Select(bone, !selection.Contains(bone));
- skinningCache.events.boneSelectionChanged.Invoke();
- }
- }
- }
- private void HandleRotateBone()
- {
- if (view.IsActionTriggering(SkeletonAction.RotateBone))
- m_Moved = false;
- var pivot = hoveredBone;
- if (view.IsActionHot(SkeletonAction.RotateBone))
- pivot = hotBone;
- if (pivot == null)
- return;
- var rootBones = selection.roots.ToSpriteSheetIfNeeded();
- pivot = pivot.FindRoot<BoneCache>(rootBones);
- if (pivot == null)
- return;
- float deltaAngle;
- if (view.DoRotateBone(pivot.position, pivot.forward, out deltaAngle))
- {
- if (!m_Moved)
- {
- skinningCache.BeginUndoOperation(TextContent.rotateBone);
- m_Moved = true;
- }
- m_Skeleton.RotateBones(selectedBones, deltaAngle);
- InvokePoseChanged();
- }
- }
- private void HandleMoveBone()
- {
- if (view.IsActionTriggering(SkeletonAction.MoveBone))
- m_Moved = false;
- Vector3 deltaPosition;
- if (view.DoMoveBone(out deltaPosition))
- {
- if (!m_Moved)
- {
- skinningCache.BeginUndoOperation(TextContent.moveBone);
- m_Moved = true;
- }
- m_Skeleton.MoveBones(rootBones, deltaPosition);
- InvokePoseChanged();
- }
- }
- private void HandleFreeMoveBone()
- {
- if (view.IsActionTriggering(SkeletonAction.FreeMoveBone))
- m_Moved = false;
- Vector3 deltaPosition;
- if (view.DoFreeMoveBone(out deltaPosition))
- {
- if (!m_Moved)
- {
- skinningCache.BeginUndoOperation(TextContent.freeMoveBone);
- m_Moved = true;
- }
- m_Skeleton.FreeMoveBones(selectedBones, deltaPosition);
- InvokePoseChanged();
- }
- }
- private void HandleMoveJoint()
- {
- if (view.IsActionTriggering(SkeletonAction.MoveJoint))
- m_Moved = false;
- if (view.IsActionFinishing(SkeletonAction.MoveJoint))
- {
- if (hoveredTail != null && hoveredTail.chainedChild == null && hotBone.parent == hoveredTail)
- hoveredTail.chainedChild = hotBone;
- }
- Vector3 deltaPosition;
- if (view.DoMoveJoint(out deltaPosition))
- {
- if (!m_Moved)
- {
- skinningCache.BeginUndoOperation(TextContent.moveJoint);
- m_Moved = true;
- }
- //Snap to parent endPosition
- if (hoveredTail != null && hoveredTail.chainedChild == null && hotBone.parent == hoveredTail)
- deltaPosition = hoveredTail.endPosition - hotBone.position;
- m_Skeleton.MoveJoints(selectedBones, deltaPosition);
- InvokePoseChanged();
- }
- }
- private void HandleMoveEndPosition()
- {
- if (view.IsActionTriggering(SkeletonAction.MoveEndPosition))
- m_Moved = false;
- if (view.IsActionFinishing(SkeletonAction.MoveEndPosition))
- {
- if (hoveredJoint != null && hoveredJoint.parent == hotBone)
- hotBone.chainedChild = hoveredJoint;
- }
- Vector3 endPosition;
- if (view.DoMoveEndPosition(out endPosition))
- {
- if (!m_Moved)
- {
- skinningCache.BeginUndoOperation(TextContent.moveEndPoint);
- m_Moved = true;
- }
- Debug.Assert(hotBone != null);
- Debug.Assert(hotBone.chainedChild == null);
- if (hoveredJoint != null && hoveredJoint.parent == hotBone)
- endPosition = hoveredJoint.position;
-
- m_Skeleton.SetEndPosition(hotBone, endPosition);
- InvokePoseChanged();
- }
- }
- private void HandleChangeLength()
- {
- if (view.IsActionTriggering(SkeletonAction.ChangeLength))
- m_Moved = false;
- Vector3 endPosition;
- if (view.DoChangeLength(out endPosition))
- {
- if (!m_Moved)
- {
- skinningCache.BeginUndoOperation(TextContent.boneLength);
- m_Moved = true;
- }
- Debug.Assert(hotBone != null);
- var direction = (Vector3)endPosition - hotBone.position;
- hotBone.length = Vector3.Dot(direction, hotBone.right);
- InvokePoseChanged();
- }
- }
- private void HandleCreateBone()
- {
- Vector3 position;
- if (view.DoCreateBoneStart(out position))
- {
- m_PrevCreatedBone = null;
- if (hoveredTail != null)
- {
- m_PrevCreatedBone = hoveredTail;
- m_CreateBoneStartPosition = hoveredTail.endPosition;
- }
- else
- {
- m_CreateBoneStartPosition = position;
- }
- }
- if (view.DoCreateBone(out position))
- {
- using (skinningCache.UndoScope(TextContent.createBone))
- {
- var isChained = m_PrevCreatedBone != null;
- var parentBone = isChained ? m_PrevCreatedBone : rootBone;
- if (isChained)
- m_CreateBoneStartPosition = m_PrevCreatedBone.endPosition;
- var name = AutoBoneName(parentBone, skeleton.bones);
- var bone = m_Skeleton.CreateBone(parentBone, m_CreateBoneStartPosition, position, isChained, name);
- m_PrevCreatedBone = bone;
- m_CreateBoneStartPosition = bone.endPosition;
- InvokeTopologyChanged();
- InvokePoseChanged();
- }
- }
- }
- private void HandleSplitBone()
- {
- int instanceID;
- Vector3 position;
- if (view.DoSplitBone(out instanceID, out position))
- {
- using (skinningCache.UndoScope(TextContent.splitBone))
- {
- var boneToSplit = GetBone(instanceID);
- Debug.Assert(boneToSplit != null);
- var splitLength = Vector3.Dot(hoveredBone.right, position - boneToSplit.position);
- var name = AutoBoneName(boneToSplit, skeleton.bones);
- m_Skeleton.SplitBone(boneToSplit, splitLength, name);
- InvokeTopologyChanged();
- InvokePoseChanged();
- }
- }
- }
- private void HandleRemoveBone()
- {
- if (view.DoRemoveBone())
- {
- using (skinningCache.UndoScope(TextContent.removeBone))
- {
- m_Skeleton.DestroyBones(selectedBones);
- selection.Clear();
- skinningCache.events.boneSelectionChanged.Invoke();
- InvokeTopologyChanged();
- InvokePoseChanged();
- }
- }
- }
- private void HandleCancelMultiStepAction()
- {
- if (view.DoCancelMultistepAction(false))
- m_PrevCreatedBone = null;
- }
- private void DrawSkeleton()
- {
- if (!view.IsRepainting())
- return;
- bool isNotOnVisualElement = !skinningCache.IsOnVisualElement();
- if (view.IsActionActive(SkeletonAction.CreateBone) || view.IsActionHot(SkeletonAction.CreateBone))
- {
- if (isNotOnVisualElement)
- {
- var endPoint = view.GetMouseWorldPosition(Vector3.forward, Vector3.zero);
- if (view.IsActionHot(SkeletonAction.CreateBone))
- endPoint = m_CreateBoneStartPosition;
- if (m_PrevCreatedBone == null && hoveredTail == null)
- {
- var root = rootBone;
- if (root != null)
- view.DrawBoneParentLink(root.position, endPoint, Vector3.forward, style.GetParentLinkPreviewColor(skeleton.BoneCount));
- }
- }
- }
- for (var i = 0; i < skeleton.BoneCount; ++i)
- {
- var bone = skeleton.GetBone(i);
- if (bone.isVisible == false || bone.parentBone == null || bone.parentBone.chainedChild == bone)
- continue;
- view.DrawBoneParentLink(bone.parent.position, bone.position, Vector3.forward, style.GetParentLinkColor(bone));
- }
- for (var i = 0; i < skeleton.BoneCount; ++i)
- {
- var bone = skeleton.GetBone(i);
- if ((view.IsActionActive(SkeletonAction.SplitBone) && hoveredBone == bone && isNotOnVisualElement) || bone.isVisible == false)
- continue;
- var isSelected = selection.Contains(bone.ToCharacterIfNeeded());
- var isHovered = hoveredBody == bone && view.IsActionHot(SkeletonAction.None) && isNotOnVisualElement;
- DrawBoneOutline(bone, style.GetOutlineColor(bone, isSelected, isHovered), style.GetOutlineScale(isSelected));
- }
- for (var i = 0; i < skeleton.BoneCount; ++i)
- {
- var bone = skeleton.GetBone(i);
- if ((view.IsActionActive(SkeletonAction.SplitBone) && hoveredBone == bone && isNotOnVisualElement) || bone.isVisible == false)
- continue;
- DrawBone(bone, style.GetColor(bone));
- }
- }
- private void DrawBone(BoneCache bone, Color color)
- {
- var isSelected = selection.Contains(bone.ToCharacterIfNeeded());
- var isNotOnVisualElement = !skinningCache.IsOnVisualElement();
- var isJointHovered = view.IsActionHot(SkeletonAction.None) && hoveredJoint == bone && isNotOnVisualElement;
- var isTailHovered = view.IsActionHot(SkeletonAction.None) && hoveredTail == bone && isNotOnVisualElement;
- view.DrawBone(bone.position, bone.right, Vector3.forward, bone.length, color, bone.chainedChild != null, isSelected, isJointHovered, isTailHovered, bone == hotBone);
- }
- private void DrawBoneOutline(BoneCache bone, Color color, float outlineScale)
- {
- view.DrawBoneOutline(bone.position, bone.right, Vector3.forward, bone.length, color, outlineScale);
- }
- private void DrawSplitBonePreview()
- {
- if (!view.IsRepainting())
- return;
- if (skinningCache.IsOnVisualElement())
- return;
- if (view.IsActionActive(SkeletonAction.SplitBone) && hoveredBone != null)
- {
- var splitLength = Vector3.Dot(hoveredBone.right, view.GetMouseWorldPosition(hoveredBone.forward, hoveredBody.position) - hoveredBone.position);
- var position = hoveredBone.position + hoveredBone.right * splitLength;
- var length = hoveredBone.length - splitLength;
- var isSelected = selection.Contains(hoveredBone.ToCharacterIfNeeded());
- {
- var color = style.GetOutlineColor(hoveredBone, false, false);
- if (color.a > 0f)
- view.DrawBoneOutline(hoveredBone.position, hoveredBone.right, Vector3.forward, splitLength, style.GetOutlineColor(hoveredBone, isSelected, true), style.GetOutlineScale(false));
-
- }
- {
- var color = style.GetPreviewOutlineColor(skeleton.BoneCount);
- if (color.a > 0f)
- view.DrawBoneOutline(position, hoveredBone.right, Vector3.forward, length, style.GetPreviewOutlineColor(skeleton.BoneCount), style.GetOutlineScale(false));
-
- }
- view.DrawBone(hoveredBone.position,
- hoveredBone.right,
- Vector3.forward,
- splitLength,
- style.GetColor(hoveredBone),
- hoveredBone.chainedChild != null,
- false, false, false, false);
- view.DrawBone(position,
- hoveredBone.right,
- Vector3.forward,
- length,
- style.GetPreviewColor(skeleton.BoneCount),
- hoveredBone.chainedChild != null,
- false, false, false, false);
- }
- }
- private void DrawCreateBonePreview()
- {
- if (!view.IsRepainting())
- return;
- if (skinningCache.IsOnVisualElement())
- return;
- var color = style.GetPreviewColor(skeleton.BoneCount);
- var outlineColor = style.GetPreviewOutlineColor(skeleton.BoneCount);
- var startPosition = m_CreateBoneStartPosition;
- var mousePosition = view.GetMouseWorldPosition(Vector3.forward, Vector3.zero);
- if (view.IsActionActive(SkeletonAction.CreateBone))
- {
- startPosition = mousePosition;
- if (hoveredTail != null)
- startPosition = hoveredTail.endPosition;
- if (outlineColor.a > 0f)
- view.DrawBoneOutline(startPosition, Vector3.right, Vector3.forward, 0f, outlineColor, style.GetOutlineScale(false));
- view.DrawBone(startPosition, Vector3.right, Vector3.forward, 0f, color, false, false, false, false, false);
- }
- if (view.IsActionHot(SkeletonAction.CreateBone))
- {
- var direction = (mousePosition - startPosition);
- if (outlineColor.a > 0f)
- view.DrawBoneOutline(startPosition, direction.normalized, Vector3.forward, direction.magnitude, outlineColor, style.GetOutlineScale(false));
- view.DrawBone(startPosition, direction.normalized, Vector3.forward, direction.magnitude, color, false, false, false, false, false);
- }
- }
- private void DrawCursors()
- {
- if (!view.IsRepainting())
- return;
- view.DrawCursors(!skinningCache.IsOnVisualElement());
- }
- public static string AutoBoneName(BoneCache parent, IEnumerable<BoneCache> bones)
- {
- string parentName = "root";
- string inheritedName;
- int counter;
- if (parent != null)
- parentName = parent.name;
- DissectBoneName(parentName, out inheritedName, out counter);
- int nameCounter = FindBiggestNameCounter(bones);
- if (inheritedName == k_DefaultRootName)
- inheritedName = k_DefaultBoneName;
- return String.Format("{0}_{1}", inheritedName, ++nameCounter);
- }
- private static int FindBiggestNameCounter(IEnumerable<BoneCache> bones)
- {
- int autoNameCounter = 0;
- string inheritedName;
- int counter;
- foreach (var bone in bones)
- {
- DissectBoneName(bone.name, out inheritedName, out counter);
- if (counter > autoNameCounter)
- autoNameCounter = counter;
- }
- return autoNameCounter;
- }
- private static void DissectBoneName(string boneName, out string inheritedName, out int counter)
- {
- if (IsBoneNameMatchAutoFormat(boneName))
- {
- var tokens = boneName.Split('_');
- var lastTokenIndex = tokens.Length - 1;
- var tokensWithoutLast = new string[lastTokenIndex];
- Array.Copy(tokens, tokensWithoutLast, lastTokenIndex);
- inheritedName = string.Join("_", tokensWithoutLast);
- counter = int.Parse(tokens[lastTokenIndex]);
- }
- else
- {
- inheritedName = boneName;
- counter = -1;
- }
- }
- private static bool IsBoneNameMatchAutoFormat(string boneName)
- {
- return s_Regex.IsMatch(boneName);
- }
- private void InvokeTopologyChanged()
- {
- skinningCache.events.skeletonTopologyChanged.Invoke(skeleton);
- }
- private void InvokePoseChanged()
- {
- skeleton.SetPosePreview();
- if (editBindPose)
- {
- skeleton.SetDefaultPose();
- skinningCache.events.skeletonBindPoseChanged.Invoke(skeleton);
- }
- else
- skinningCache.events.skeletonPreviewPoseChanged.Invoke(skeleton);
- }
- }
- }
|