testss
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D.Animation;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
[CustomEditor(typeof(Bone))]
|
||||
[CanEditMultipleObjects]
|
||||
class BoneEditor : Editor
|
||||
{
|
||||
static class Style
|
||||
{
|
||||
public static GUIContent boneId = new GUIContent("Bone ID", "The ID of the bone where this GameObject Transform should associate to for SpriteSkin auto rebinding.");
|
||||
}
|
||||
private SerializedProperty m_GUID;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_GUID = serializedObject.FindProperty("m_Guid");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_GUID, Style.boneId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,470 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D;
|
||||
using UnityEngine.U2D.Animation;
|
||||
using UnityEngine.U2D.Common;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
//Make sure Bone Gizmo registers callbacks before anyone else
|
||||
[InitializeOnLoad]
|
||||
internal class BoneGizmoInitializer
|
||||
{
|
||||
static BoneGizmoInitializer()
|
||||
{
|
||||
BoneGizmo.instance.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
internal class BoneGizmo : ScriptableSingleton<BoneGizmo>
|
||||
{
|
||||
private BoneGizmoController m_BoneGizmoController;
|
||||
|
||||
internal BoneGizmoController boneGizmoController { get { return m_BoneGizmoController; } }
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
m_BoneGizmoController = new BoneGizmoController(new SkeletonView(new GUIWrapper()), new UnityEngineUndo(), new BoneGizmoToggle());
|
||||
RegisterCallbacks();
|
||||
}
|
||||
|
||||
internal void ClearSpriteBoneCache()
|
||||
{
|
||||
boneGizmoController.ClearSpriteBoneCache();
|
||||
}
|
||||
|
||||
private void RegisterCallbacks()
|
||||
{
|
||||
Selection.selectionChanged += OnSelectionChanged;
|
||||
SceneView.duringSceneGui += OnSceneGUI;
|
||||
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
|
||||
EditorApplication.playModeStateChanged += PlayModeStateChanged;
|
||||
}
|
||||
|
||||
private void OnSceneGUI(SceneView sceneView)
|
||||
{
|
||||
boneGizmoController.OnGUI();
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
boneGizmoController.OnSelectionChanged();
|
||||
}
|
||||
|
||||
private void OnAfterAssemblyReload()
|
||||
{
|
||||
boneGizmoController.OnSelectionChanged();
|
||||
}
|
||||
|
||||
private void PlayModeStateChanged(PlayModeStateChange stateChange)
|
||||
{
|
||||
if (stateChange == PlayModeStateChange.EnteredPlayMode ||
|
||||
stateChange == PlayModeStateChange.EnteredEditMode)
|
||||
boneGizmoController.OnSelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
internal class BoneGizmoController
|
||||
{
|
||||
private Dictionary<Sprite, UnityEngine.U2D.SpriteBone[]> m_SpriteBones = new Dictionary<Sprite, UnityEngine.U2D.SpriteBone[]>();
|
||||
private Dictionary<Transform, Vector2> m_BoneData = new Dictionary<Transform, Vector2>();
|
||||
private HashSet<SpriteSkin> m_SkinComponents = new HashSet<SpriteSkin>();
|
||||
private HashSet<Transform> m_CachedBones = new HashSet<Transform>();
|
||||
private HashSet<Transform> m_SelectionRoots = new HashSet<Transform>();
|
||||
private ISkeletonView view;
|
||||
private IUndo m_Undo;
|
||||
private Tool m_PreviousTool = Tool.None;
|
||||
private IBoneGizmoToggle m_BoneGizmoToggle;
|
||||
|
||||
internal IBoneGizmoToggle boneGizmoToggle { get { return m_BoneGizmoToggle; } set { m_BoneGizmoToggle = value; } }
|
||||
|
||||
public Transform hoveredBone
|
||||
{
|
||||
get { return GetBone(view.hoveredBoneID); }
|
||||
}
|
||||
public Transform hoveredTail
|
||||
{
|
||||
get { return GetBone(view.hoveredTailID); }
|
||||
}
|
||||
public Transform hoveredBody
|
||||
{
|
||||
get { return GetBone(view.hoveredBodyID); }
|
||||
}
|
||||
public Transform hoveredJoint
|
||||
{
|
||||
get { return GetBone(view.hoveredJointID); }
|
||||
}
|
||||
public Transform hotBone
|
||||
{
|
||||
get { return GetBone(view.hotBoneID); }
|
||||
}
|
||||
|
||||
private Transform GetBone(int instanceID)
|
||||
{
|
||||
return EditorUtility.InstanceIDToObject(instanceID) as Transform;
|
||||
}
|
||||
|
||||
public BoneGizmoController(ISkeletonView view, IUndo undo, IBoneGizmoToggle toggle)
|
||||
{
|
||||
this.view = view;
|
||||
view.mode = SkeletonMode.EditPose;
|
||||
view.InvalidID = 0;
|
||||
m_Undo = undo;
|
||||
m_BoneGizmoToggle = toggle;
|
||||
}
|
||||
|
||||
internal void OnSelectionChanged()
|
||||
{
|
||||
m_SelectionRoots.Clear();
|
||||
|
||||
foreach (var selectedTransform in Selection.transforms)
|
||||
{
|
||||
var prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(selectedTransform.gameObject);
|
||||
var animator = default(Animator);
|
||||
|
||||
if (prefabRoot != null)
|
||||
m_SelectionRoots.Add(prefabRoot.transform);
|
||||
else if ((animator = selectedTransform.GetComponentInParent<Animator>()) != null)
|
||||
m_SelectionRoots.Add(animator.transform);
|
||||
else
|
||||
m_SelectionRoots.Add(selectedTransform.root);
|
||||
}
|
||||
|
||||
if (m_PreviousTool == Tool.None && Selection.activeTransform != null && m_BoneData.ContainsKey(Selection.activeTransform))
|
||||
{
|
||||
m_PreviousTool = UnityEditor.Tools.current;
|
||||
UnityEditor.Tools.current = Tool.None;
|
||||
}
|
||||
|
||||
if (m_PreviousTool != Tool.None && (Selection.activeTransform == null || !m_BoneData.ContainsKey(Selection.activeTransform)))
|
||||
{
|
||||
if (UnityEditor.Tools.current == Tool.None)
|
||||
UnityEditor.Tools.current = m_PreviousTool;
|
||||
|
||||
m_PreviousTool = Tool.None;
|
||||
}
|
||||
|
||||
FindSkinComponents();
|
||||
}
|
||||
|
||||
internal void OnGUI()
|
||||
{
|
||||
m_BoneGizmoToggle.OnGUI();
|
||||
|
||||
if (!m_BoneGizmoToggle.enableGizmos)
|
||||
return;
|
||||
|
||||
PrepareBones();
|
||||
DoBoneGUI();
|
||||
}
|
||||
|
||||
internal void FindSkinComponents()
|
||||
{
|
||||
m_SkinComponents.Clear();
|
||||
|
||||
foreach (var root in m_SelectionRoots)
|
||||
{
|
||||
var components = root.GetComponentsInChildren<SpriteSkin>(false);
|
||||
|
||||
foreach (var component in components)
|
||||
m_SkinComponents.Add(component);
|
||||
}
|
||||
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
internal void ClearSpriteBoneCache()
|
||||
{
|
||||
m_SpriteBones.Clear();
|
||||
}
|
||||
|
||||
private void PrepareBones()
|
||||
{
|
||||
if (!view.CanLayout())
|
||||
return;
|
||||
|
||||
if (view.IsActionHot(SkeletonAction.None))
|
||||
m_CachedBones.Clear();
|
||||
|
||||
m_BoneData.Clear();
|
||||
|
||||
foreach (var skinComponent in m_SkinComponents)
|
||||
{
|
||||
if (skinComponent == null)
|
||||
continue;
|
||||
|
||||
PrepareBones(skinComponent);
|
||||
}
|
||||
}
|
||||
|
||||
private UnityEngine.U2D.SpriteBone[] GetSpriteBones(SpriteSkin spriteSkin)
|
||||
{
|
||||
Debug.Assert(spriteSkin.isValid);
|
||||
|
||||
var sprite = spriteSkin.spriteRenderer.sprite;
|
||||
UnityEngine.U2D.SpriteBone[] spriteBones;
|
||||
if (!m_SpriteBones.TryGetValue(sprite, out spriteBones))
|
||||
{
|
||||
spriteBones = sprite.GetBones();
|
||||
m_SpriteBones[sprite] = sprite.GetBones();
|
||||
}
|
||||
|
||||
return spriteBones;
|
||||
}
|
||||
|
||||
private void PrepareBones(SpriteSkin spriteSkin)
|
||||
{
|
||||
Debug.Assert(spriteSkin != null);
|
||||
Debug.Assert(view.CanLayout());
|
||||
|
||||
if (!spriteSkin.isActiveAndEnabled || !spriteSkin.isValid || !spriteSkin.spriteRenderer.enabled)
|
||||
return;
|
||||
|
||||
var sprite = spriteSkin.spriteRenderer.sprite;
|
||||
var boneTransforms = spriteSkin.boneTransforms;
|
||||
var spriteBones = GetSpriteBones(spriteSkin);
|
||||
var alpha = 1f;
|
||||
|
||||
if (spriteBones == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < boneTransforms.Length; ++i)
|
||||
{
|
||||
var boneTransform = boneTransforms[i];
|
||||
|
||||
if (boneTransform == null || m_BoneData.ContainsKey(boneTransform))
|
||||
continue;
|
||||
|
||||
var bone = spriteBones[i];
|
||||
|
||||
if (view.IsActionHot(SkeletonAction.None))
|
||||
m_CachedBones.Add(boneTransform);
|
||||
|
||||
m_BoneData.Add(boneTransform, new Vector2(bone.length, alpha));
|
||||
}
|
||||
}
|
||||
|
||||
private void DoBoneGUI()
|
||||
{
|
||||
view.BeginLayout();
|
||||
|
||||
if (view.CanLayout())
|
||||
LayoutBones();
|
||||
|
||||
view.EndLayout();
|
||||
|
||||
HandleSelectBone();
|
||||
HandleRotateBone();
|
||||
HandleMoveBone();
|
||||
DrawBones();
|
||||
DrawCursors();
|
||||
}
|
||||
|
||||
private void LayoutBones()
|
||||
{
|
||||
foreach (var bone in m_CachedBones)
|
||||
{
|
||||
if (bone == null)
|
||||
continue;
|
||||
|
||||
Vector2 value;
|
||||
if (!m_BoneData.TryGetValue(bone, out value))
|
||||
continue;
|
||||
|
||||
var length = value.x;
|
||||
|
||||
if (bone != hotBone)
|
||||
view.LayoutBone(bone.GetInstanceID(), bone.position, bone.position + bone.GetScaledRight() * length, bone.forward, bone.up, bone.right, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSelectBone()
|
||||
{
|
||||
int instanceID;
|
||||
bool additive;
|
||||
if (view.DoSelectBone(out instanceID, out additive))
|
||||
{
|
||||
var bone = GetBone(instanceID);
|
||||
|
||||
if (!additive)
|
||||
{
|
||||
if (!Selection.Contains(bone.gameObject))
|
||||
Selection.activeTransform = bone;
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectList = new List<Object>(Selection.objects);
|
||||
|
||||
if(objectList.Contains(bone.gameObject))
|
||||
objectList.Remove(bone.gameObject);
|
||||
else
|
||||
objectList.Add(bone.gameObject);
|
||||
|
||||
Selection.objects = objectList.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleRotateBone()
|
||||
{
|
||||
var pivot = hoveredBone;
|
||||
|
||||
if (view.IsActionHot(SkeletonAction.RotateBone))
|
||||
pivot = hotBone;
|
||||
|
||||
if (pivot == null)
|
||||
return;
|
||||
|
||||
FindPivotTransform(pivot, out pivot);
|
||||
|
||||
if (pivot == null)
|
||||
return;
|
||||
|
||||
float deltaAngle;
|
||||
if (view.DoRotateBone(pivot.position, pivot.forward, out deltaAngle))
|
||||
SetBoneRotation(deltaAngle);
|
||||
}
|
||||
|
||||
private void HandleMoveBone()
|
||||
{
|
||||
Vector3 deltaPosition;
|
||||
if (view.DoMoveBone(out deltaPosition))
|
||||
SetBonePosition(deltaPosition);
|
||||
}
|
||||
|
||||
private bool FindPivotTransform(Transform transform, out Transform selectedTransform)
|
||||
{
|
||||
selectedTransform = transform;
|
||||
var selectedRoots = Selection.transforms;
|
||||
|
||||
foreach(var selectedRoot in selectedRoots)
|
||||
{
|
||||
if(transform.IsDescendentOf(selectedRoot))
|
||||
{
|
||||
selectedTransform = selectedRoot;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SetBonePosition(Vector3 deltaPosition)
|
||||
{
|
||||
foreach (var selectedTransform in Selection.transforms)
|
||||
{
|
||||
if(!m_BoneData.ContainsKey(selectedTransform))
|
||||
continue;
|
||||
|
||||
var boneTransform = selectedTransform;
|
||||
|
||||
m_Undo.RecordObject(boneTransform, TextContent.moveBone);
|
||||
boneTransform.position += deltaPosition;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBoneRotation(float deltaAngle)
|
||||
{
|
||||
foreach(var selectedGameObject in Selection.gameObjects)
|
||||
{
|
||||
if(!m_BoneData.ContainsKey(selectedGameObject.transform))
|
||||
continue;
|
||||
|
||||
var boneTransform = selectedGameObject.transform;
|
||||
|
||||
m_Undo.RecordObject(boneTransform, TextContent.rotateBone);
|
||||
boneTransform.Rotate(boneTransform.forward, deltaAngle, Space.World);
|
||||
InternalEngineBridge.SetLocalEulerHint(boneTransform);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBones()
|
||||
{
|
||||
if (!view.IsRepainting())
|
||||
return;
|
||||
|
||||
var selectedOutlineColor = SelectionOutlineSettings.outlineColor;
|
||||
var selectedOutlineSize = SelectionOutlineSettings.selectedBoneOutlineSize;
|
||||
var defaultOutlineColor = Color.black.AlphaMultiplied(0.5f);
|
||||
|
||||
//Draw bone outlines
|
||||
foreach (var boneData in m_BoneData)
|
||||
{
|
||||
var bone = boneData.Key;
|
||||
|
||||
if (bone == null)
|
||||
continue;
|
||||
|
||||
var value = boneData.Value;
|
||||
var length = value.x;
|
||||
var alpha = value.y;
|
||||
|
||||
if (alpha == 0f || !bone.gameObject.activeInHierarchy)
|
||||
continue;
|
||||
|
||||
var color = defaultOutlineColor;
|
||||
var outlineSize = 1.25f;
|
||||
|
||||
var isSelected = Selection.Contains(bone.gameObject);
|
||||
var isHovered = hoveredBody == bone && view.IsActionHot(SkeletonAction.None);
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
color = selectedOutlineColor;
|
||||
outlineSize = selectedOutlineSize * 0.5f + 1f;
|
||||
}
|
||||
else if (isHovered)
|
||||
color = Handles.preselectionColor;
|
||||
|
||||
DrawBoneOutline(bone, length, color, outlineSize);
|
||||
}
|
||||
|
||||
//Draw bones
|
||||
foreach (var boneData in m_BoneData)
|
||||
{
|
||||
var bone = boneData.Key;
|
||||
|
||||
if (bone == null)
|
||||
continue;
|
||||
|
||||
var value = boneData.Value;
|
||||
var length = value.x;
|
||||
var alpha = value.y;
|
||||
|
||||
if (alpha == 0f || !bone.gameObject.activeInHierarchy)
|
||||
continue;
|
||||
|
||||
DrawBone(bone, length, Color.white);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBone(Transform bone, float length, Color color)
|
||||
{
|
||||
var isSelected = Selection.Contains(bone.gameObject);
|
||||
var isJointHovered = view.IsActionHot(SkeletonAction.None) && hoveredJoint == bone;
|
||||
var isTailHovered = view.IsActionHot(SkeletonAction.None) && hoveredTail == bone;
|
||||
|
||||
view.DrawBone(bone.position, bone.GetScaledRight(), bone.forward, length, color, false, isSelected, isJointHovered, isTailHovered, bone == hotBone);
|
||||
}
|
||||
|
||||
private void DrawBoneOutline(Transform bone, float length, Color color, float outlineScale)
|
||||
{
|
||||
view.DrawBoneOutline(bone.position, bone.GetScaledRight(), bone.forward, length, color, outlineScale);
|
||||
}
|
||||
|
||||
private void DrawCursors()
|
||||
{
|
||||
if (!view.IsRepainting())
|
||||
return;
|
||||
|
||||
view.DrawCursors(true);
|
||||
}
|
||||
|
||||
private bool HasParentBone(Transform transform)
|
||||
{
|
||||
Debug.Assert(transform != null);
|
||||
|
||||
return transform.parent != null && m_BoneData.ContainsKey(transform.parent);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D.Animation;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal interface IBoneGizmoToggle
|
||||
{
|
||||
bool enableGizmos { get; }
|
||||
void OnGUI();
|
||||
}
|
||||
|
||||
internal class BoneGizmoToggle : IBoneGizmoToggle
|
||||
{
|
||||
private bool m_EnableGizmos;
|
||||
private bool m_CurrentEnableGizmoState;
|
||||
|
||||
public bool enableGizmos
|
||||
{
|
||||
get { return m_CurrentEnableGizmoState; }
|
||||
}
|
||||
|
||||
public BoneGizmoToggle()
|
||||
{
|
||||
SpriteSkin.onDrawGizmos.AddListener(OnDrawGizmos);
|
||||
}
|
||||
|
||||
~BoneGizmoToggle()
|
||||
{
|
||||
SpriteSkin.onDrawGizmos.RemoveListener(OnDrawGizmos);
|
||||
}
|
||||
|
||||
//This callback will be called before OnSceneGUI in a Repaint event
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
m_EnableGizmos = true;
|
||||
|
||||
//One time is enough
|
||||
SpriteSkin.onDrawGizmos.RemoveListener(OnDrawGizmos);
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
//Ignore events other than Repaint
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
return;
|
||||
|
||||
if (m_CurrentEnableGizmoState != m_EnableGizmos)
|
||||
SceneView.RepaintAll();
|
||||
|
||||
m_CurrentEnableGizmoState = m_EnableGizmos;
|
||||
|
||||
//Assume the Gizmo toggle is disabled and listen to the event again
|
||||
m_EnableGizmos = false;
|
||||
SpriteSkin.onDrawGizmos.RemoveListener(OnDrawGizmos);
|
||||
SpriteSkin.onDrawGizmos.AddListener(OnDrawGizmos);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
#if ENABLE_ANIMATION_COLLECTION && ENABLE_ANIMATION_BURST
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D.Animation;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class SpriteSkinCompositeDebugWindow : EditorWindow
|
||||
{
|
||||
[MenuItem("internal:Window/2D/SpritSkinCompositeDebug")]
|
||||
static void Launch()
|
||||
{
|
||||
EditorWindow.GetWindow<SpriteSkinCompositeDebugWindow>().Show();
|
||||
}
|
||||
|
||||
Vector2 m_ScrollPos = Vector2.zero;
|
||||
string m_DebugLog = "";
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (GUILayout.Button("Reset Sprite SkinComposite"))
|
||||
SpriteSkinComposite.instance.ResetComposite();
|
||||
|
||||
if (GUILayout.Button("Show Debug"))
|
||||
{
|
||||
m_DebugLog = SpriteSkinComposite.instance.GetDebugLog();
|
||||
}
|
||||
|
||||
m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos);
|
||||
GUILayout.TextArea(m_DebugLog);
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,377 @@
|
||||
#if ENABLE_ANIMATION_COLLECTION && ENABLE_ANIMATION_BURST
|
||||
#define ENABLE_ANIMATION_PERFORMANCE
|
||||
#endif
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine.U2D.Animation;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine.U2D;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
[CustomEditor(typeof(SpriteSkin))]
|
||||
[CanEditMultipleObjects]
|
||||
class SpriteSkinEditor : Editor
|
||||
{
|
||||
private static class Contents
|
||||
{
|
||||
public static readonly GUIContent listHeaderLabel = new GUIContent("Bones", "GameObject Transform to represent the Bones defined by the Sprite that is currently used for deformation.");
|
||||
public static readonly GUIContent rootBoneLabel = new GUIContent("Root Bone", "GameObject Transform to represent the Root Bone.");
|
||||
public static readonly string spriteNotFound = L10n.Tr("Sprite not found in SpriteRenderer");
|
||||
public static readonly string spriteHasNoSkinningInformation = L10n.Tr("Sprite has no Bind Poses");
|
||||
public static readonly string spriteHasNoWeights = L10n.Tr("Sprite has no weights");
|
||||
public static readonly string rootTransformNotFound = L10n.Tr("Root Bone not set");
|
||||
public static readonly string rootTransformNotFoundInArray = L10n.Tr("Bone list doesn't contain a reference to the Root Bone");
|
||||
public static readonly string invalidTransformArray = L10n.Tr("Bone list is invalid");
|
||||
public static readonly string transformArrayContainsNull = L10n.Tr("Bone list contains unassigned references");
|
||||
public static readonly string invalidTransformArrayLength = L10n.Tr("The number of Sprite's Bind Poses and the number of Transforms should match");
|
||||
public static readonly GUIContent useManager = new GUIContent("Enable batching", "When enabled, SpriteSkin deformation will be done in batch to improve performance.");
|
||||
public static readonly GUIContent alwaysUpdate = new GUIContent("Always Update", "Executes deformation of SpriteSkin even when the associated SpriteRenderer has been culled and is not visible.");
|
||||
public static readonly GUIContent autoRebind = new GUIContent("Auto Rebind", "When the Sprite in SpriteRenderer is changed, SpriteSkin will try to look for the Transforms that is needed for the Sprite using the Root Bone Tranform as parent.");
|
||||
public static readonly string enableBatchingHelp = L10n.Tr("Install Burst and Collection package to enable deformation batching.");
|
||||
}
|
||||
|
||||
private static Color s_BoundingBoxHandleColor = new Color(255, 255, 255, 150) / 255;
|
||||
|
||||
private SerializedProperty m_RootBoneProperty;
|
||||
private SerializedProperty m_BoneTransformsProperty;
|
||||
private SerializedProperty m_AlwaysUpdateProperty;
|
||||
private SerializedProperty m_AutoRebindProperty;
|
||||
private SpriteSkin m_SpriteSkin;
|
||||
private ReorderableList m_ReorderableList;
|
||||
private Sprite m_CurrentSprite;
|
||||
private BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle();
|
||||
private bool m_NeedsRebind = false;
|
||||
private SerializedProperty m_UseBatching;
|
||||
private bool m_BoneFold = true;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_SpriteSkin = (SpriteSkin)target;
|
||||
m_SpriteSkin.OnEditorEnable();
|
||||
|
||||
m_RootBoneProperty = serializedObject.FindProperty("m_RootBone");
|
||||
m_UseBatching = serializedObject.FindProperty("m_UseBatching");
|
||||
|
||||
m_BoneTransformsProperty = serializedObject.FindProperty("m_BoneTransforms");
|
||||
m_AlwaysUpdateProperty = serializedObject.FindProperty("m_AlwaysUpdate");
|
||||
m_AutoRebindProperty = serializedObject.FindProperty("m_AutoRebind");
|
||||
|
||||
m_CurrentSprite = m_SpriteSkin.spriteRenderer.sprite;
|
||||
m_BoundsHandle.axes = BoxBoundsHandle.Axes.X | BoxBoundsHandle.Axes.Y;
|
||||
m_BoundsHandle.SetColor(s_BoundingBoxHandleColor);
|
||||
|
||||
SetupReorderableList();
|
||||
|
||||
Undo.undoRedoPerformed += UndoRedoPerformed;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Undo.undoRedoPerformed -= UndoRedoPerformed;
|
||||
}
|
||||
|
||||
private void UndoRedoPerformed()
|
||||
{
|
||||
m_CurrentSprite = m_SpriteSkin.spriteRenderer.sprite;
|
||||
}
|
||||
|
||||
private void SetupReorderableList()
|
||||
{
|
||||
m_ReorderableList = new ReorderableList(serializedObject, m_BoneTransformsProperty, false, true, false, false);
|
||||
m_ReorderableList.headerHeight = 1.0f;
|
||||
m_ReorderableList.elementHeightCallback = (int index) =>
|
||||
{
|
||||
return EditorGUIUtility.singleLineHeight + 6;
|
||||
};
|
||||
m_ReorderableList.drawElementCallback = (Rect rect, int index, bool isactive, bool isfocused) =>
|
||||
{
|
||||
var content = GUIContent.none;
|
||||
|
||||
if (m_CurrentSprite != null)
|
||||
{
|
||||
var bones = m_CurrentSprite.GetBones();
|
||||
if (index < bones.Length)
|
||||
content = new GUIContent(bones[index].name);
|
||||
}
|
||||
|
||||
rect.y += 2f;
|
||||
rect.height = EditorGUIUtility.singleLineHeight;
|
||||
SerializedProperty element = m_BoneTransformsProperty.GetArrayElementAtIndex(index);
|
||||
EditorGUI.PropertyField(rect, element, content);
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeBoneTransformArray()
|
||||
{
|
||||
if (m_CurrentSprite)
|
||||
{
|
||||
var elementCount = m_BoneTransformsProperty.arraySize;
|
||||
var bones = m_CurrentSprite.GetBones();
|
||||
|
||||
if (elementCount != bones.Length)
|
||||
{
|
||||
m_BoneTransformsProperty.arraySize = bones.Length;
|
||||
|
||||
for (int i = elementCount; i < m_BoneTransformsProperty.arraySize; ++i)
|
||||
m_BoneTransformsProperty.GetArrayElementAtIndex(i).objectReferenceValue = null;
|
||||
|
||||
m_NeedsRebind = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
EditorGUILayout.PropertyField(m_AlwaysUpdateProperty, Contents.alwaysUpdate);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(m_AutoRebindProperty, Contents.autoRebind);
|
||||
if (EditorGUI.EndChangeCheck() && m_AutoRebindProperty.boolValue)
|
||||
{
|
||||
m_NeedsRebind = true;
|
||||
}
|
||||
|
||||
var sprite = m_SpriteSkin.spriteRenderer.sprite;
|
||||
var spriteChanged = m_CurrentSprite != sprite;
|
||||
|
||||
if (m_ReorderableList == null || spriteChanged)
|
||||
{
|
||||
m_CurrentSprite = sprite;
|
||||
InitializeBoneTransformArray();
|
||||
SetupReorderableList();
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(m_RootBoneProperty, Contents.rootBoneLabel);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
m_NeedsRebind = true;
|
||||
}
|
||||
|
||||
m_BoneFold = EditorGUILayout.Foldout(m_BoneFold, Contents.listHeaderLabel, true);
|
||||
if (m_BoneFold)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
if (!serializedObject.isEditingMultipleObjects)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(m_SpriteSkin.rootBone == null);
|
||||
m_ReorderableList.DoLayoutList();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!EnableCreateBones());
|
||||
DoGenerateBonesButton();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!EnableSetBindPose());
|
||||
DoResetBindPoseButton();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
#if !ENABLE_ANIMATION_PERFORMANCE
|
||||
EditorGUILayout.HelpBox(Contents.enableBatchingHelp, MessageType.Info);
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
#endif
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(m_UseBatching, Contents.useManager);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
foreach (var obj in targets)
|
||||
{
|
||||
((SpriteSkin)obj).UseBatching(m_UseBatching.boolValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
if (m_NeedsRebind)
|
||||
Rebind();
|
||||
|
||||
if (spriteChanged && !m_SpriteSkin.ignoreNextSpriteChange)
|
||||
{
|
||||
ResetBounds(Undo.GetCurrentGroupName());
|
||||
m_SpriteSkin.ignoreNextSpriteChange = false;
|
||||
}
|
||||
|
||||
DoValidationWarnings();
|
||||
}
|
||||
|
||||
private void Rebind()
|
||||
{
|
||||
foreach (var t in targets)
|
||||
{
|
||||
var spriteSkin = t as SpriteSkin;
|
||||
|
||||
if(spriteSkin.spriteRenderer.sprite == null || spriteSkin.rootBone == null)
|
||||
continue;
|
||||
var spriteBones = spriteSkin.spriteRenderer.sprite.GetBones();
|
||||
var transforms = new Transform[spriteBones.Length];
|
||||
if (SpriteSkin.GetSpriteBonesTransforms(spriteBones, spriteSkin.rootBone, transforms))
|
||||
spriteSkin.boneTransforms = transforms;
|
||||
|
||||
ResetBoundsIfNeeded(spriteSkin);
|
||||
}
|
||||
|
||||
serializedObject.Update();
|
||||
m_NeedsRebind = false;
|
||||
}
|
||||
|
||||
private void ResetBounds(string undoName = "Reset Bounds")
|
||||
{
|
||||
foreach (var t in targets)
|
||||
{
|
||||
var spriteSkin = t as SpriteSkin;
|
||||
|
||||
if (!spriteSkin.isValid)
|
||||
continue;
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(spriteSkin, undoName);
|
||||
spriteSkin.CalculateBounds();
|
||||
|
||||
EditorUtility.SetDirty(spriteSkin);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetBoundsIfNeeded(SpriteSkin spriteSkin)
|
||||
{
|
||||
if (spriteSkin.isValid && spriteSkin.bounds == new Bounds())
|
||||
spriteSkin.CalculateBounds();
|
||||
}
|
||||
|
||||
private bool EnableCreateBones()
|
||||
{
|
||||
foreach (var t in targets)
|
||||
{
|
||||
var spriteSkin = t as SpriteSkin;
|
||||
var sprite = spriteSkin.spriteRenderer.sprite;
|
||||
|
||||
if (sprite != null && spriteSkin.rootBone == null)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool EnableSetBindPose()
|
||||
{
|
||||
return IsAnyTargetValid();
|
||||
}
|
||||
|
||||
private bool IsAnyTargetValid()
|
||||
{
|
||||
foreach (var t in targets)
|
||||
{
|
||||
var spriteSkin = t as SpriteSkin;
|
||||
|
||||
if (spriteSkin.isValid)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void DoGenerateBonesButton()
|
||||
{
|
||||
if (GUILayout.Button("Create Bones", GUILayout.MaxWidth(125f)))
|
||||
{
|
||||
foreach (var t in targets)
|
||||
{
|
||||
var spriteSkin = t as SpriteSkin;
|
||||
var sprite = spriteSkin.spriteRenderer.sprite;
|
||||
|
||||
if (sprite == null || spriteSkin.rootBone != null)
|
||||
continue;
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(spriteSkin, "Create Bones");
|
||||
|
||||
spriteSkin.CreateBoneHierarchy();
|
||||
|
||||
foreach (var transform in spriteSkin.boneTransforms)
|
||||
Undo.RegisterCreatedObjectUndo(transform.gameObject, "Create Bones");
|
||||
|
||||
ResetBoundsIfNeeded(spriteSkin);
|
||||
|
||||
EditorUtility.SetDirty(spriteSkin);
|
||||
}
|
||||
BoneGizmo.instance.boneGizmoController.OnSelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoResetBindPoseButton()
|
||||
{
|
||||
if (GUILayout.Button("Reset Bind Pose", GUILayout.MaxWidth(125f)))
|
||||
{
|
||||
foreach (var t in targets)
|
||||
{
|
||||
var spriteSkin = t as SpriteSkin;
|
||||
|
||||
if (!spriteSkin.isValid)
|
||||
continue;
|
||||
|
||||
Undo.RecordObjects(spriteSkin.boneTransforms, "Reset Bind Pose");
|
||||
spriteSkin.ResetBindPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DoValidationWarnings()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
bool preAppendObjectName = targets.Length > 1;
|
||||
|
||||
foreach (var t in targets)
|
||||
{
|
||||
var spriteSkin = t as SpriteSkin;
|
||||
|
||||
var validationResult = spriteSkin.Validate();
|
||||
|
||||
if (validationResult == SpriteSkinValidationResult.Ready)
|
||||
continue;
|
||||
|
||||
var text = "";
|
||||
|
||||
switch (validationResult)
|
||||
{
|
||||
case SpriteSkinValidationResult.SpriteNotFound:
|
||||
text = Contents.spriteNotFound;
|
||||
break;
|
||||
case SpriteSkinValidationResult.SpriteHasNoSkinningInformation:
|
||||
text = Contents.spriteHasNoSkinningInformation;
|
||||
break;
|
||||
case SpriteSkinValidationResult.SpriteHasNoWeights:
|
||||
text = Contents.spriteHasNoWeights;
|
||||
break;
|
||||
case SpriteSkinValidationResult.RootTransformNotFound:
|
||||
text = Contents.rootTransformNotFound;
|
||||
break;
|
||||
case SpriteSkinValidationResult.RootNotFoundInTransformArray:
|
||||
text = Contents.rootTransformNotFoundInArray;
|
||||
break;
|
||||
case SpriteSkinValidationResult.InvalidTransformArray:
|
||||
text = Contents.invalidTransformArray;
|
||||
break;
|
||||
case SpriteSkinValidationResult.InvalidTransformArrayLength:
|
||||
text = Contents.invalidTransformArrayLength;
|
||||
break;
|
||||
case SpriteSkinValidationResult.TransformArrayContainsNull:
|
||||
text = Contents.transformArrayContainsNull;
|
||||
break;
|
||||
}
|
||||
|
||||
if (preAppendObjectName)
|
||||
text = string.Format("{0}:{1}",spriteSkin.name,text);
|
||||
|
||||
EditorGUILayout.HelpBox(text, MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal static class TransformExtensions
|
||||
{
|
||||
public static Vector3 GetScaledRight(this Transform transform)
|
||||
{
|
||||
return transform.localToWorldMatrix.MultiplyVector(Vector3.right);
|
||||
}
|
||||
|
||||
public static Vector3 GetScaledUp(this Transform transform)
|
||||
{
|
||||
return transform.localToWorldMatrix.MultiplyVector(Vector3.up);
|
||||
}
|
||||
|
||||
public static bool IsDescendentOf(this Transform transform, Transform ancestor)
|
||||
{
|
||||
if (ancestor != null)
|
||||
{
|
||||
var parent = transform.parent;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent == ancestor)
|
||||
return true;
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user