using System.Collections.Generic; using System.Linq; using UnityEngine; namespace UnityEditor.U2D.Animation { internal class SkeletonCache : TransformCache { [SerializeField] bool m_IsPosePreview = false; [SerializeField] List m_Bones = new List(); public bool isPosePreview => m_IsPosePreview; public int boneCount => m_Bones.Count; public virtual BoneCache[] bones => m_Bones.ToArray(); public void AddBone(BoneCache bone, bool worldPositionStays = true) { Debug.Assert(bone != null); Debug.Assert(!Contains(bone)); if (bone.parent == null) bone.SetParent(this, worldPositionStays); m_Bones.Add(bone); } public void ReorderBones(IEnumerable boneCache) { if (boneCache.Count() == m_Bones.Count) { foreach (var b in m_Bones) { if (!boneCache.Contains(b)) return; } m_Bones = boneCache.ToList(); } } public void DestroyBone(BoneCache bone) { Debug.Assert(bone != null); Debug.Assert(Contains(bone)); m_Bones.Remove(bone); var boneChildren = bone.children; foreach (var child in boneChildren) child.SetParent(bone.parent); skinningCache.Destroy(bone); } public void SetDefaultPose() { foreach (var bone in m_Bones) bone.SetDefaultPose(); m_IsPosePreview = false; } public void RestoreDefaultPose() { foreach (var bone in m_Bones) bone.RestoreDefaultPose(); m_IsPosePreview = false; skinningCache.events.skeletonPreviewPoseChanged.Invoke(this); } public void SetPosePreview() { m_IsPosePreview = true; } public BonePose[] GetLocalPose() { var pose = new List(); foreach (var bone in m_Bones) pose.Add(bone.localPose); return pose.ToArray(); } public void SetLocalPose(BonePose[] pose) { Debug.Assert(m_Bones.Count == pose.Length); for (var i = 0; i < m_Bones.Count; ++i) m_Bones[i].localPose = pose[i]; m_IsPosePreview = true; } public BonePose[] GetWorldPose() { var pose = new List(); foreach (var bone in m_Bones) pose.Add(bone.worldPose); return pose.ToArray(); } public void SetWorldPose(BonePose[] pose) { Debug.Assert(m_Bones.Count == pose.Length); for (var i = 0; i < m_Bones.Count; ++i) { var bone = m_Bones[i]; var childWoldPose = bone.GetChildrenWoldPose(); bone.worldPose = pose[i]; bone.SetChildrenWorldPose(childWoldPose); } m_IsPosePreview = true; } public BoneCache GetBone(int index) { return m_Bones[index]; } public int IndexOf(BoneCache bone) { return m_Bones.IndexOf(bone); } public bool Contains(BoneCache bone) { return m_Bones.Contains(bone); } public void Clear() { var roots = children; foreach (var root in roots) DestroyHierarchy(root); m_Bones.Clear(); } public string GetUniqueName(BoneCache bone) { Debug.Assert(Contains(bone)); var boneName = bone.name; var names = m_Bones.ConvertAll(b => b.name); var index = IndexOf(bone); var count = 0; Debug.Assert(index < names.Count); for (var i = 0; i < index; ++i) if (names[i].Equals(boneName)) ++count; return count == 0 ? boneName : $"{boneName} ({count + 1})"; } void DestroyHierarchy(TransformCache root) { Debug.Assert(root != null); var rootChildren = root.children; foreach (var child in rootChildren) DestroyHierarchy(child); skinningCache.Destroy(root); } } }