rimworld-animation-studio/Library/PackageCache/com.unity.2d.animation@3.2.6/Editor/SpriteSkin/SpriteSkinEditor.cs
2022-09-13 00:36:34 -05:00

369 lines
14 KiB
C#

#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;
using UnityEngine.U2D.Common;
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 string experimental = L10n.Tr("Experimental");
}
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 SpriteSkin m_SpriteSkin;
private ReorderableList m_ReorderableList;
private Sprite m_CurrentSprite;
private BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle();
private bool m_NeedsRebind = false;
#if ENABLE_ANIMATION_PERFORMANCE
private SerializedProperty m_UseBatching;
private bool m_ExperimentalFold;
#endif
private bool m_BoneFold = true;
private void OnEnable()
{
m_SpriteSkin = (SpriteSkin)target;
m_SpriteSkin.OnEditorEnable();
m_RootBoneProperty = serializedObject.FindProperty("m_RootBone");
#if ENABLE_ANIMATION_PERFORMANCE
m_UseBatching = serializedObject.FindProperty("m_UseBatching");
#endif
m_BoneTransformsProperty = serializedObject.FindProperty("m_BoneTransforms");
m_AlwaysUpdateProperty = serializedObject.FindProperty("m_AlwaysUpdate");
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 bindPoses = m_CurrentSprite.GetBindPoses();
if (elementCount != bindPoses.Length)
{
m_BoneTransformsProperty.arraySize = bindPoses.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);
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
m_ExperimentalFold = EditorGUILayout.Foldout(m_ExperimentalFold, Contents.experimental, true);
if (m_ExperimentalFold)
{
EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_UseBatching, Contents.useManager);
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in targets)
{
((SpriteSkin)obj).UseBatching(m_UseBatching.boolValue);
}
}
EditorGUI.indentLevel--;
}
#endif
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;
spriteSkin.Rebind();
ResetBoundsIfNeeded(spriteSkin);
}
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 = spriteSkin.name + ": " + text;
EditorGUILayout.HelpBox(text, MessageType.Warning);
}
}
}
}