[unity] More SkeletonDebugWindow, improved inspectors and icons for SpineAttributeDrawers!

This commit is contained in:
pharan 2017-05-17 15:50:09 +08:00
parent fd8ed4d175
commit a43bdc4361
18 changed files with 438 additions and 118 deletions

View File

@ -120,7 +120,7 @@ namespace Spine.Unity.Editor {
}
if (materials.arraySize == 0) {
EditorGUILayout.LabelField(new GUIContent("Error: Missing materials", SpineEditorUtilities.Icons.warning));
EditorGUILayout.HelpBox("Missing materials", MessageType.Error);
return;
}
@ -128,7 +128,7 @@ namespace Spine.Unity.Editor {
SerializedProperty prop = materials.GetArrayElementAtIndex(i);
Material mat = (Material)prop.objectReferenceValue;
if (mat == null) {
EditorGUILayout.LabelField(new GUIContent("Error: Materials cannot be null", SpineEditorUtilities.Icons.warning));
EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error);
return;
}
}

View File

@ -126,7 +126,7 @@ namespace Spine.Unity.Editor {
if (serializedObject.isEditingMultipleObjects) {
using (new SpineInspectorUtility.BoxScope()) {
EditorGUILayout.LabelField("SkeletonData", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(skeletonJSON, new GUIContent(skeletonJSON.displayName, Icons.spine));
EditorGUILayout.PropertyField(skeletonJSON, SpineInspectorUtility.TempContent(skeletonJSON.displayName, Icons.spine));
EditorGUILayout.PropertyField(scale);
}
@ -162,7 +162,7 @@ namespace Spine.Unity.Editor {
serializedObject.Update();
EditorGUILayout.LabelField(new GUIContent(target.name + " (SkeletonDataAsset)", Icons.spine), EditorStyles.whiteLargeLabel);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(target.name + " (SkeletonDataAsset)", Icons.spine), EditorStyles.whiteLargeLabel);
if (m_skeletonData != null) {
EditorGUILayout.LabelField("(Drag and Drop to instantiate.)", EditorStyles.miniLabel);
}
@ -181,7 +181,7 @@ namespace Spine.Unity.Editor {
// }
}
EditorGUILayout.PropertyField(skeletonJSON, new GUIContent(skeletonJSON.displayName, Icons.spine));
EditorGUILayout.PropertyField(skeletonJSON, SpineInspectorUtility.TempContent(skeletonJSON.displayName, Icons.spine));
EditorGUILayout.PropertyField(scale);
}
@ -239,7 +239,7 @@ namespace Spine.Unity.Editor {
#if !SPINE_TK2D
// Reimport Button
using (new EditorGUI.DisabledGroupScope(skeletonJSON.objectReferenceValue == null)) {
if (GUILayout.Button(new GUIContent("Attempt Reimport", Icons.warning))) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Attempt Reimport", Icons.warning))) {
DoReimport();
}
}
@ -249,7 +249,7 @@ namespace Spine.Unity.Editor {
// List warnings.
foreach (var line in warnings)
EditorGUILayout.LabelField(new GUIContent(line, Icons.warning));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(line, Icons.warning));
}
if (!Application.isPlaying)
@ -259,16 +259,16 @@ namespace Spine.Unity.Editor {
void DrawUnityTools () {
#if SPINE_SKELETON_ANIMATOR
using (new SpineInspectorUtility.BoxScope()) {
isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, new GUIContent("SkeletonAnimator", Icons.unityIcon));
isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", Icons.unityIcon));
if (isMecanimExpanded) {
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(controller, new GUIContent("Controller", Icons.controllerIcon));
EditorGUILayout.PropertyField(controller, SpineInspectorUtility.TempContent("Controller", Icons.controllerIcon));
if (controller.objectReferenceValue == null) {
// Generate Mecanim Controller Button
using (new GUILayout.HorizontalScope()) {
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button(new GUIContent("Generate Mecanim Controller"), GUILayout.Height(20)))
if (GUILayout.Button(SpineInspectorUtility.TempContent("Generate Mecanim Controller"), GUILayout.Height(20)))
SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset);
}
EditorGUILayout.HelpBox("SkeletonAnimator is the Mecanim alternative to SkeletonAnimation.\nIt is not required.", MessageType.Info);
@ -278,7 +278,7 @@ namespace Spine.Unity.Editor {
// Update AnimationClips button.
using (new GUILayout.HorizontalScope()) {
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button(new GUIContent("Force Update AnimationClips"), GUILayout.Height(20)))
if (GUILayout.Button(SpineInspectorUtility.TempContent("Force Update AnimationClips"), GUILayout.Height(20)))
SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset);
}
@ -414,12 +414,12 @@ namespace Spine.Unity.Editor {
}
void DrawAnimationList () {
showAnimationList = EditorGUILayout.Foldout(showAnimationList, new GUIContent(string.Format("Animations [{0}]", m_skeletonData.Animations.Count), Icons.animationRoot));
showAnimationList = EditorGUILayout.Foldout(showAnimationList, SpineInspectorUtility.TempContent(string.Format("Animations [{0}]", m_skeletonData.Animations.Count), Icons.animationRoot));
if (!showAnimationList)
return;
if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
if (GUILayout.Button(new GUIContent("Setup Pose", Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Setup Pose", Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
StopAnimation();
m_skeletonAnimation.skeleton.SetToSetupPose();
m_requireRefresh = true;
@ -428,7 +428,7 @@ namespace Spine.Unity.Editor {
EditorGUILayout.HelpBox("Animations can be previewed if you expand the Preview window below.", MessageType.Info);
}
EditorGUILayout.LabelField("Name", "Duration");
EditorGUILayout.LabelField("Name", " Duration");
foreach (Spine.Animation animation in m_skeletonData.Animations) {
using (new GUILayout.HorizontalScope()) {
if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
@ -445,13 +445,13 @@ namespace Spine.Unity.Editor {
} else {
GUILayout.Label("-", GUILayout.Width(24));
}
EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), new GUIContent(animation.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(animation.Duration * 30)) + ")").PadLeft(12, ' ')));
EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), SpineInspectorUtility.TempContent(animation.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(animation.Duration * 30)) + ")").PadLeft(12, ' ')));
}
}
}
void DrawSlotList () {
showSlotList = EditorGUILayout.Foldout(showSlotList, new GUIContent("Slots", Icons.slotRoot));
showSlotList = EditorGUILayout.Foldout(showSlotList, SpineInspectorUtility.TempContent("Slots", Icons.slotRoot));
if (!showSlotList) return;
if (m_skeletonAnimation == null || m_skeletonAnimation.skeleton == null) return;
@ -467,7 +467,7 @@ namespace Spine.Unity.Editor {
for (int i = m_skeletonAnimation.skeleton.Slots.Count - 1; i >= 0; i--) {
Slot slot = slotsItems[i];
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, Icons.slot));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot));
if (showAttachments) {
EditorGUI.indentLevel++;
@ -491,7 +491,7 @@ namespace Spine.Unity.Editor {
string attachmentName = slotAttachmentNames[a];
Texture2D icon = Icons.GetAttachmentIcon(attachment);
bool initialState = slot.Attachment == attachment;
bool toggled = EditorGUILayout.ToggleLeft(new GUIContent(attachmentName, icon), slot.Attachment == attachment);
bool toggled = EditorGUILayout.ToggleLeft(SpineInspectorUtility.TempContent(attachmentName, icon), slot.Attachment == attachment);
if (!defaultSkinAttachmentNames.Contains(attachmentName)) {
Rect skinPlaceHolderIconRect = GUILayoutUtility.GetLastRect();
@ -831,13 +831,13 @@ namespace Spine.Unity.Editor {
popRect.x += 4;
popRect.height = 24;
popRect.width = 40;
EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", Icons.skinsRoot));
EditorGUI.DropShadowLabel(popRect, SpineInspectorUtility.TempContent("Skin"));
popRect.y += 11;
popRect.width = 150;
popRect.x += 44;
if (GUI.Button(popRect, label, EditorStyles.popup)) {
if (GUI.Button(popRect, SpineInspectorUtility.TempContent(label, Icons.skin), EditorStyles.popup)) {
DrawSkinDropdown();
}
}
@ -954,7 +954,7 @@ namespace Spine.Unity.Editor {
*/
public override GUIContent GetPreviewTitle () {
return new GUIContent("Preview");
return SpineInspectorUtility.TempContent("Preview");
}
public override void OnPreviewSettings () {
@ -997,7 +997,7 @@ namespace Spine.Unity.Editor {
void DrawSkinDropdown () {
var menu = new GenericMenu();
foreach (Skin s in m_skeletonData.Skins)
menu.AddItem(new GUIContent(s.Name), this.m_skeletonAnimation.skeleton.Skin == s, SetSkin, s);
menu.AddItem(new GUIContent(s.Name, Icons.skin), this.m_skeletonAnimation.skeleton.Skin == s, SetSkin, s);
menu.ShowAsContext();
}

View File

@ -167,16 +167,14 @@ namespace Spine.Unity.Editor {
bool hasCollider2D = targetBoneFollower.GetComponent<Collider2D>() != null || targetBoneFollower.GetComponent<BoundingBoxFollower>() != null;
bool hasCollider3D = !hasCollider2D && targetBoneFollower.GetComponent<Collider>();
if (hasCollider2D || hasCollider3D) {
if (targetBoneFollower.GetComponent<Rigidbody2D>() == null) {
using (new SpineInspectorUtility.BoxScope()) {
EditorGUILayout.HelpBox("Collider detected. Unity recommends adding a Rigidbody to the parent Transforms of any colliders that are intended to be dynamically repositioned and rotated.", MessageType.Warning);
string rbLabel = hasCollider2D ? "Add Rigidbody2D" : "Add Rigidbody";
var rbType = hasCollider2D ? typeof(Rigidbody2D) : typeof(Rigidbody);
var rbContent = new GUIContent(rbLabel, "Add a rigidbody to this GameObject to be the Box2D parent of the attached collider.");
rbContent.image = EditorGUIUtility.ObjectContent(null, rbType).image;
if (SpineInspectorUtility.CenteredButton(rbContent)) targetBoneFollower.gameObject.AddComponent(rbType);
}
bool missingRigidBody = (hasCollider2D && targetBoneFollower.GetComponent<Rigidbody2D>() == null) || (hasCollider3D && targetBoneFollower.GetComponent<Rigidbody>() == null);
if (missingRigidBody) {
using (new SpineInspectorUtility.BoxScope()) {
EditorGUILayout.HelpBox("Collider detected. Unity recommends adding a Rigidbody to the parent Transforms of any colliders that are intended to be dynamically repositioned and rotated.", MessageType.Warning);
var rbType = hasCollider2D ? typeof(Rigidbody2D) : typeof(Rigidbody);
string rbLabel = string.Format("Add {0}", rbType.Name);
var rbContent = SpineInspectorUtility.TempContent(rbLabel, SpineInspectorUtility.UnityIcon(rbType), "Add a rigidbody to this GameObject to be the Box2D parent of the attached collider.");
if (SpineInspectorUtility.CenteredButton(rbContent)) targetBoneFollower.gameObject.AddComponent(rbType);
}
}
} else {

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 04ae56b3698d3e844844cfcef2f009e7
timeCreated: 1494928093
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -88,6 +88,7 @@ namespace Spine.Unity.Editor {
EditorGUILayout.PropertyField(timeScale, TimeScaleLabel);
var component = (SkeletonAnimation)target;
component.timeScale = Mathf.Max(component.timeScale, 0);
EditorGUILayout.Space();
}
if (!isInspectingPrefab) {

View File

@ -42,6 +42,7 @@ namespace Spine.Unity.Editor {
public class SkeletonDebugWindow : EditorWindow {
const bool IsUtilityWindow = true;
internal static bool showBoneNames, showPaths = true, showShapes = true, showConstraints = true;
[MenuItem("CONTEXT/SkeletonRenderer/Open Skeleton Debug Window", false, 5000)]
public static void Init () {
@ -79,7 +80,28 @@ namespace Spine.Unity.Editor {
readonly Dictionary<Slot, List<Attachment>> attachmentTable = new Dictionary<Slot, List<Attachment>>();
static bool staticLostValues = true;
void OnSceneGUI (SceneView sceneView) {
if (skeleton == null || skeletonRenderer == null || !skeletonRenderer.valid || isPrefab)
return;
var transform = skeletonRenderer.transform;
if (showPaths) SpineHandles.DrawPaths(transform, skeleton);
if (showConstraints) SpineHandles.DrawConstraints(transform, skeleton);
if (showBoneNames) SpineHandles.DrawBoneNames(transform, skeleton);
if (showShapes) SpineHandles.DrawBoundingBoxes(transform, skeleton);
if (bone != null) {
SpineHandles.DrawBone(skeletonRenderer.transform, bone, 1.5f, Color.cyan);
Handles.Label(bone.GetWorldPosition(skeletonRenderer.transform) + (Vector3.down * 0.15f), bone.Data.Name, SpineHandles.BoneNameStyle);
}
}
void OnSelectionChange () {
SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
SceneView.onSceneGUIDelegate += this.OnSceneGUI;
bool noSkeletonRenderer = false;
var selectedObject = Selection.activeGameObject;
@ -90,6 +112,11 @@ namespace Spine.Unity.Editor {
if (selectedSkeletonRenderer == null) {
noSkeletonRenderer = true;
} else if (skeletonRenderer != selectedSkeletonRenderer) {
bone = null;
if (skeletonRenderer != null && skeletonRenderer.SkeletonDataAsset != selectedSkeletonRenderer.SkeletonDataAsset)
boneName = null;
skeletonRenderer = selectedSkeletonRenderer;
skeletonRenderer.Initialize(false);
skeletonRenderer.LateUpdate();
@ -99,19 +126,43 @@ namespace Spine.Unity.Editor {
}
}
if (noSkeletonRenderer) {
skeletonRenderer = null;
skeleton = null;
attachmentTable.Clear();
isPrefab = false;
boneName = string.Empty;
bone = null;
}
if (noSkeletonRenderer) Clear();
Repaint();
}
void Clear () {
skeletonRenderer = null;
skeleton = null;
attachmentTable.Clear();
isPrefab = false;
boneName = string.Empty;
bone = null;
SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
}
void OnDestroy () {
Clear();
}
static void FalseDropDown (string label, string stringValue, Texture2D icon = null, bool disabledGroup = false) {
if (disabledGroup) EditorGUI.BeginDisabledGroup(true);
var pos = EditorGUILayout.GetControlRect(true);
pos = EditorGUI.PrefixLabel(pos, SpineInspectorUtility.TempContent(label));
GUI.Button(pos, SpineInspectorUtility.TempContent(stringValue, icon), EditorStyles.popup);
if (disabledGroup) EditorGUI.EndDisabledGroup();
}
// Window GUI
void OnGUI () {
bool requireRepaint = false;
if (staticLostValues) {
Clear();
OnSelectionChange();
staticLostValues = false;
requireRepaint = true;
}
if (SlotsRootLabel == null) {
SlotsRootLabel = new GUIContent("Slots", Icons.slotRoot);
SkeletonRootLabel = new GUIContent("Skeleton", Icons.skeleton);
@ -121,21 +172,24 @@ namespace Spine.Unity.Editor {
BoldFoldoutStyle.fixedWidth = 0;
}
bool requireRepaint = false;
EditorGUILayout.Space();
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField("Debug Selection", skeletonRenderer, typeof(SkeletonRenderer), true);
EditorGUILayout.ObjectField(SpineInspectorUtility.TempContent("Debug Selection", Icons.spine), skeletonRenderer, typeof(SkeletonRenderer), true);
EditorGUI.EndDisabledGroup();
if (skeleton == null || skeletonRenderer == null || !skeletonRenderer.valid) return;
if (skeleton == null || skeletonRenderer == null) {
EditorGUILayout.HelpBox("No SkeletonRenderer Spine GameObject selected.", MessageType.Info);
return;
}
if (isPrefab) {
GUILayout.Label(new GUIContent("Cannot edit Prefabs", Icons.warning));
EditorGUILayout.HelpBox("SkeletonDebug only debugs Spine GameObjects in the scene.", MessageType.Warning);
return;
}
if (!skeletonRenderer.valid) {
GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", Icons.warning));
EditorGUILayout.HelpBox("Spine Component is invalid. Check SkeletonData Asset.", MessageType.Error);
return;
}
@ -145,7 +199,7 @@ namespace Spine.Unity.Editor {
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
using (new SpineInspectorUtility.BoxScope(false)) {
if (SpineInspectorUtility.CenteredButton(new GUIContent("Skeleton.SetToSetupPose()"))) {
if (SpineInspectorUtility.CenteredButton(SpineInspectorUtility.TempContent("Skeleton.SetToSetupPose()"))) {
skeleton.SetToSetupPose();
requireRepaint = true;
}
@ -153,10 +207,10 @@ namespace Spine.Unity.Editor {
EditorGUI.BeginChangeCheck();
EditorGUILayout.LabelField("Scene View", EditorStyles.boldLabel);
using (new SpineInspectorUtility.LabelWidthScope()) {
SkeletonRendererInspector.showBoneNames = EditorGUILayout.Toggle("Show Bone Names", SkeletonRendererInspector.showBoneNames);
SkeletonRendererInspector.showPaths = EditorGUILayout.Toggle("Show Paths", SkeletonRendererInspector.showPaths);
SkeletonRendererInspector.showShapes = EditorGUILayout.Toggle("Show Shapes", SkeletonRendererInspector.showShapes);
SkeletonRendererInspector.showConstraints = EditorGUILayout.Toggle("Show Constraints", SkeletonRendererInspector.showConstraints);
showBoneNames = EditorGUILayout.Toggle("Show Bone Names", showBoneNames);
showPaths = EditorGUILayout.Toggle("Show Paths", showPaths);
showShapes = EditorGUILayout.Toggle("Show Shapes", showShapes);
showConstraints = EditorGUILayout.Toggle("Show Constraints", showConstraints);
}
requireRepaint |= EditorGUI.EndChangeCheck();
@ -168,6 +222,10 @@ namespace Spine.Unity.Editor {
using (new EditorGUILayout.FadeGroupScope(showSkeleton.faded)) {
EditorGUI.BeginChangeCheck();
EditorGUI.BeginDisabledGroup(true);
FalseDropDown(".Skin", skeleton.Skin != null ? skeletonRenderer.Skeleton.Skin.Name : "<None>", Icons.skin);
EditorGUI.EndDisabledGroup();
// Flip
EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(160f));
EditorGUILayout.LabelField("Flip", GUILayout.MaxWidth(EditorGUIUtility.labelWidth - 20f));
@ -184,12 +242,13 @@ namespace Spine.Unity.Editor {
}
// Bone
showInspectBoneTree.target = EditorGUILayout.Foldout(showInspectBoneTree.target, new GUIContent("Bone", Icons.bone), BoldFoldoutStyle);
showInspectBoneTree.target = EditorGUILayout.Foldout(showInspectBoneTree.target, SpineInspectorUtility.TempContent("Bone", Icons.bone), BoldFoldoutStyle);
if (showInspectBoneTree.faded > 0) {
using (new SpineInspectorUtility.IndentScope()) {
using (new EditorGUILayout.FadeGroupScope(showInspectBoneTree.faded)) {
showBoneNames = EditorGUILayout.Toggle("Show Bone Names", showBoneNames);
if (bpo == null) bpo = new SerializedObject(this).FindProperty("boneName");
EditorGUILayout.PropertyField(bpo);
EditorGUILayout.PropertyField(bpo, SpineInspectorUtility.TempContent("Bone"));
if (!string.IsNullOrEmpty(bpo.stringValue)) {
if (bone == null || bone.Data.Name != bpo.stringValue) {
bone = skeleton.FindBone(bpo.stringValue);
@ -197,18 +256,48 @@ namespace Spine.Unity.Editor {
if (bone != null) {
using (new EditorGUI.DisabledGroupScope(true)) {
var boneParent = bone.Parent;
if (boneParent != null) EditorGUILayout.TextField("parent", boneParent.Data.Name);
var wm = EditorGUIUtility.wideMode;
EditorGUIUtility.wideMode = true;
EditorGUILayout.Slider("Local Rotation", ViewRound(bone.Rotation), -180f, 180f);
EditorGUILayout.Vector2Field("Local Position", RoundVector2(bone.X, bone.Y));
EditorGUILayout.Vector2Field("Local Scale", RoundVector2(bone.ScaleX, bone.ScaleY));
EditorGUILayout.Vector2Field("Local Shear", RoundVector2(bone.ShearX, bone.ShearY));
EditorGUILayout.Space();
EditorGUILayout.Slider("Local Rotation", bone.Rotation, -180f, 180f);
EditorGUILayout.Vector2Field("Local Position", new Vector2(bone.X, bone.Y));
EditorGUILayout.Vector2Field("Local Scale", new Vector2(bone.ScaleX, bone.ScaleY));
EditorGUILayout.Vector2Field("Local Shear", new Vector2(bone.ShearX, bone.ShearY));
// EditorGUILayout.Space();
// EditorGUILayout.LabelField("LocalToWorld Matrix");
// EditorGUILayout.Vector2Field("AB", new Vector2(bone.A, bone.B));
// EditorGUILayout.Vector2Field("CD", new Vector2(bone.C, bone.D));
var boneParent = bone.Parent;
if (boneParent != null) FalseDropDown("Parent", boneParent.Data.Name, Icons.bone);
const string RoundFormat = "0.##";
var lw = EditorGUIUtility.labelWidth;
var fw = EditorGUIUtility.fieldWidth;
EditorGUIUtility.labelWidth *= 0.25f;
EditorGUIUtility.fieldWidth *= 0.5f;
EditorGUILayout.LabelField("LocalToWorld");
EditorGUILayout.BeginHorizontal();
EditorGUILayout.Space();
EditorGUILayout.TextField(".A", bone.A.ToString(RoundFormat));
EditorGUILayout.TextField(".B", bone.B.ToString(RoundFormat));
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.Space();
EditorGUILayout.TextField(".C", bone.C.ToString(RoundFormat));
EditorGUILayout.TextField(".D", bone.D.ToString(RoundFormat));
EditorGUILayout.EndHorizontal();
EditorGUIUtility.labelWidth = lw * 0.5f;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.TextField(".WorldX", bone.WorldX.ToString(RoundFormat));
EditorGUILayout.TextField(".WorldY", bone.WorldY.ToString(RoundFormat));
EditorGUILayout.EndHorizontal();
EditorGUIUtility.labelWidth = lw;
EditorGUIUtility.fieldWidth = fw;
EditorGUIUtility.wideMode = wm;
}
}
requireRepaint = true;
@ -224,7 +313,7 @@ namespace Spine.Unity.Editor {
showSlotsTree.target = EditorGUILayout.Foldout(showSlotsTree.target, SlotsRootLabel, BoldFoldoutStyle);
if (showSlotsTree.faded > 0) {
using (new EditorGUILayout.FadeGroupScope(showSlotsTree.faded)) {
if (SpineInspectorUtility.CenteredButton(new GUIContent("Skeleton.SetSlotsToSetupPose()"))) {
if (SpineInspectorUtility.CenteredButton(SpineInspectorUtility.TempContent("Skeleton.SetSlotsToSetupPose()"))) {
skeleton.SetSlotsToSetupPose();
requireRepaint = true;
}
@ -235,7 +324,7 @@ namespace Spine.Unity.Editor {
using (new EditorGUILayout.HorizontalScope()) {
EditorGUI.indentLevel = baseIndent + 1;
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
EditorGUI.BeginChangeCheck();
Color c = EditorGUILayout.ColorField(new Color(slot.R, slot.G, slot.B, slot.A), GUILayout.Width(60));
if (EditorGUI.EndChangeCheck()) {
@ -249,7 +338,7 @@ namespace Spine.Unity.Editor {
EditorGUI.indentLevel = baseIndent + 2;
var icon = Icons.GetAttachmentIcon(attachment);
bool isAttached = (attachment == slot.Attachment);
bool swap = EditorGUILayout.ToggleLeft(new GUIContent(attachment.Name, icon), attachment == slot.Attachment);
bool swap = EditorGUILayout.ToggleLeft(SpineInspectorUtility.TempContent(attachment.Name, icon), attachment == slot.Attachment);
if (isAttached != swap) {
slot.Attachment = isAttached ? null : attachment;
requireRepaint = true;
@ -263,18 +352,24 @@ namespace Spine.Unity.Editor {
// Constraints
const string NoneText = "<none>";
showConstraintsTree.target = EditorGUILayout.Foldout(showConstraintsTree.target, new GUIContent("Constraints", Icons.constraintRoot), BoldFoldoutStyle);
showConstraintsTree.target = EditorGUILayout.Foldout(showConstraintsTree.target, SpineInspectorUtility.TempContent("Constraints", Icons.constraintRoot), BoldFoldoutStyle);
if (showConstraintsTree.faded > 0) {
using (new SpineInspectorUtility.IndentScope()) {
using (new EditorGUILayout.FadeGroupScope(showConstraintsTree.faded)) {
const float MixMin = 0f;
const float MixMax = 1f;
EditorGUI.BeginChangeCheck();
showConstraints = EditorGUILayout.Toggle("Show Constraints", showConstraints);
requireRepaint |= EditorGUI.EndChangeCheck();
EditorGUILayout.LabelField(new GUIContent(string.Format("IK Constraints ({0})", skeleton.IkConstraints.Count), Icons.constraintIK), EditorStyles.boldLabel);
EditorGUILayout.Space();
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(string.Format("IK Constraints ({0})", skeleton.IkConstraints.Count), Icons.constraintIK), EditorStyles.boldLabel);
using (new SpineInspectorUtility.IndentScope()) {
if (skeleton.IkConstraints.Count > 0) {
foreach (var c in skeleton.IkConstraints) {
EditorGUILayout.LabelField(new GUIContent(c.Data.Name, Icons.constraintIK));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintIK));
FalseDropDown("Goal", c.Data.Target.Name, Icons.bone, true);
EditorGUI.BeginChangeCheck();
c.Mix = EditorGUILayout.Slider("Mix", c.Mix, MixMin, MixMax);
@ -289,11 +384,14 @@ namespace Spine.Unity.Editor {
}
}
EditorGUILayout.LabelField(new GUIContent(string.Format("Transform Constraints ({0})", skeleton.TransformConstraints.Count), Icons.constraintTransform), EditorStyles.boldLabel);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(string.Format("Transform Constraints ({0})", skeleton.TransformConstraints.Count), Icons.constraintTransform), EditorStyles.boldLabel);
using (new SpineInspectorUtility.IndentScope()) {
if (skeleton.TransformConstraints.Count > 0) {
foreach (var c in skeleton.TransformConstraints) {
EditorGUILayout.LabelField(new GUIContent(c.Data.Name, Icons.constraintTransform));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintTransform));
EditorGUI.BeginDisabledGroup(true);
FalseDropDown("Goal", c.Data.Target.Name, Icons.bone);
EditorGUI.EndDisabledGroup();
EditorGUI.BeginChangeCheck();
c.TranslateMix = EditorGUILayout.Slider("TranslateMix", c.TranslateMix, MixMin, MixMax);
@ -309,14 +407,24 @@ namespace Spine.Unity.Editor {
}
}
EditorGUILayout.LabelField(new GUIContent(string.Format("Path Constraints ({0})", skeleton.PathConstraints.Count), Icons.constraintPath), EditorStyles.boldLabel);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(string.Format("Path Constraints ({0})", skeleton.PathConstraints.Count), Icons.constraintPath), EditorStyles.boldLabel);
EditorGUI.BeginChangeCheck();
showPaths = EditorGUILayout.Toggle("Show Paths", showPaths);
requireRepaint |= EditorGUI.EndChangeCheck();
using (new SpineInspectorUtility.IndentScope()) {
if (skeleton.PathConstraints.Count > 0) {
foreach (var c in skeleton.PathConstraints) {
EditorGUILayout.LabelField(new GUIContent(c.Data.Name, Icons.constraintPath));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintPath));
EditorGUI.BeginDisabledGroup(true);
FalseDropDown("Path Slot", c.Data.Target.Name, Icons.slot);
var activeAttachment = c.Target.Attachment;
FalseDropDown("Active Path", activeAttachment != null ? activeAttachment.Name : "<None>", activeAttachment is PathAttachment ? Icons.path : null);
EditorGUILayout.LabelField("PositionMode." + c.Data.PositionMode);
EditorGUILayout.LabelField("SpacingMode." + c.Data.SpacingMode);
EditorGUILayout.LabelField("RotateMode." + c.Data.RotateMode);
EditorGUI.EndDisabledGroup();
EditorGUI.BeginChangeCheck();
c.RotateMix = EditorGUILayout.Slider("RotateMix", c.RotateMix, MixMin, MixMax);
@ -336,26 +444,28 @@ namespace Spine.Unity.Editor {
}
}
showDrawOrderTree.target = EditorGUILayout.Foldout(showDrawOrderTree.target, new GUIContent("Draw Order and Separators", Icons.slotRoot), BoldFoldoutStyle);
showDrawOrderTree.target = EditorGUILayout.Foldout(showDrawOrderTree.target, SpineInspectorUtility.TempContent("Draw Order and Separators", Icons.slotRoot), BoldFoldoutStyle);
if (showDrawOrderTree.faded > 0) {
using (new SpineInspectorUtility.IndentScope()) {
using (new EditorGUILayout.FadeGroupScope(showDrawOrderTree.faded)) {
const string SeparatorString = "------------- v SEPARATOR v -------------";
if (Application.isPlaying) {
foreach (var slot in skeleton.DrawOrder) {
if (skeletonRenderer.separatorSlots.Contains(slot)) EditorGUILayout.LabelField("------");
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
if (skeletonRenderer.separatorSlots.Contains(slot)) EditorGUILayout.LabelField(SeparatorString);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
}
} else {
foreach (var slot in skeleton.DrawOrder) {
var slotNames = skeletonRenderer.separatorSlotNames;
for (int i = 0, n = slotNames.Length; i < n; i++) {
if (string.Equals(slotNames[i], slot.Data.Name, System.StringComparison.Ordinal)) {
EditorGUILayout.LabelField("------");
EditorGUILayout.LabelField(SeparatorString);
break;
}
}
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false));
}
}
@ -363,13 +473,13 @@ namespace Spine.Unity.Editor {
}
}
showEventDataTree.target = EditorGUILayout.Foldout(showEventDataTree.target, new GUIContent("Events", Icons.userEvent), BoldFoldoutStyle);
showEventDataTree.target = EditorGUILayout.Foldout(showEventDataTree.target, SpineInspectorUtility.TempContent("Events", Icons.userEvent), BoldFoldoutStyle);
if (showEventDataTree.faded > 0) {
using (new SpineInspectorUtility.IndentScope()) {
using (new EditorGUILayout.FadeGroupScope(showEventDataTree.faded)) {
if (skeleton.Data.Events.Count > 0) {
foreach (var e in skeleton.Data.Events) {
EditorGUILayout.LabelField(new GUIContent(e.Name, Icons.userEvent));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(e.Name, Icons.userEvent));
}
} else {
EditorGUILayout.LabelField(NoneText);
@ -378,6 +488,8 @@ namespace Spine.Unity.Editor {
}
}
// TODO: Data counts. bones, slots, constraints, skins, etc...
if (IsAnimating(showSlotsTree, showSkeleton, showConstraintsTree, showDrawOrderTree, showEventDataTree, showInspectBoneTree))
Repaint();
}
@ -391,6 +503,18 @@ namespace Spine.Unity.Editor {
EditorGUILayout.EndScrollView();
}
static float ViewRound (float x) {
const float Factor = 100f;
const float Divisor = 1f/Factor;
return Mathf.Round(x * Factor) * Divisor;
}
static Vector2 RoundVector2 (float x, float y) {
const float Factor = 100f;
const float Divisor = 1f/Factor;
return new Vector2(Mathf.Round(x * Factor) * Divisor, Mathf.Round(y * Factor) * Divisor);
}
static bool IsAnimating (params AnimBool[] animBools) {
foreach (var a in animBools)
if (a.isAnimating) return true;

View File

@ -42,7 +42,6 @@ namespace Spine.Unity.Editor {
[CanEditMultipleObjects]
public class SkeletonRendererInspector : UnityEditor.Editor {
protected static bool advancedFoldout;
internal static bool showBoneNames, showPaths, showShapes, showConstraints = true;
protected SerializedProperty skeletonDataAsset, initialSkinName;
protected SerializedProperty initialFlipX, initialFlipY;
@ -131,6 +130,9 @@ namespace Spine.Unity.Editor {
}
}
GUIContent[] skins;
ExposedList<Skin> loadedSkinList;
protected virtual void DrawInspectorGUI (bool multi) {
bool valid = TargetIsValid;
var reloadWidth = GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20);
@ -216,17 +218,27 @@ namespace Spine.Unity.Editor {
// Initial skin name.
if (component.valid) {
string[] skins = new string[component.skeleton.Data.Skins.Count];
var skeletonDataSkins = component.skeleton.Data.Skins;
int skinCount = skeletonDataSkins.Count;
if (loadedSkinList != skeletonDataSkins) {
skins = new GUIContent[skinCount];
loadedSkinList = skeletonDataSkins;
for (int i = 0; i < skins.Length; i++) {
string skinNameString = skeletonDataSkins.Items[i].Name;
skins[i] = new GUIContent(skinNameString, Icons.skin);
}
}
int skinIndex = 0;
for (int i = 0; i < skins.Length; i++) {
string skinNameString = component.skeleton.Data.Skins.Items[i].Name;
skins[i] = skinNameString;
string skinNameString = skeletonDataSkins.Items[i].Name;
if (skinNameString == initialSkinName.stringValue)
skinIndex = i;
}
skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins);
skinIndex = EditorGUILayout.Popup(SpineInspectorUtility.TempContent("Initial Skin"), skinIndex, skins);
if (skins.Length > 0) // Support attachmentless/skinless SkeletonData.
initialSkinName.stringValue = skins[skinIndex];
initialSkinName.stringValue = skins[skinIndex].text;
}
}
@ -268,7 +280,6 @@ namespace Spine.Unity.Editor {
if (singleSubmesh != null) EditorGUILayout.PropertyField(singleSubmesh, SingleSubmeshLabel);
if (meshes != null) EditorGUILayout.PropertyField(meshes, MeshesLabel);
if (immutableTriangles != null) EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
EditorGUILayout.PropertyField(tintBlack, TintBlackLabel);
EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
EditorGUILayout.Space();
}
@ -283,8 +294,10 @@ namespace Spine.Unity.Editor {
EditorGUILayout.Space();
using (new SpineInspectorUtility.LabelWidthScope()) {
EditorGUILayout.LabelField("Vertex Data", EditorStyles.boldLabel);
//EditorGUILayout.LabelField("Vertex Data", EditorStyles.boldLabel);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", EditorGUIUtility.ObjectContent(null, typeof(MeshFilter)).image as Texture2D), EditorStyles.boldLabel);
if (pmaVertexColors != null) EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel);
EditorGUILayout.PropertyField(tintBlack, TintBlackLabel);
// Optional fields. May be disabled in SkeletonRenderer.
if (normals != null) EditorGUILayout.PropertyField(normals, NormalsLabel);
@ -344,7 +357,7 @@ namespace Spine.Unity.Editor {
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
const string SeparatorsDescription = "Stored names of slots where the Skeleton's render will be split into different batches. This is used by separate components that split the render into different MeshRenderers or GameObjects.";
if (separatorSlotNames.isExpanded) {
EditorGUILayout.PropertyField(separatorSlotNames, new GUIContent(separatorSlotNames.displayName + terminalSlotWarning, SeparatorsDescription), true);
EditorGUILayout.PropertyField(separatorSlotNames, SpineInspectorUtility.TempContent(separatorSlotNames.displayName + terminalSlotWarning, Icons.slotRoot, SeparatorsDescription), true);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("+", GUILayout.MaxWidth(28f), GUILayout.MaxHeight(15f))) {
@ -364,11 +377,7 @@ namespace Spine.Unity.Editor {
var transform = skeletonRenderer.transform;
if (skeleton == null) return;
if (showPaths) SpineHandles.DrawPaths(transform, skeleton);
SpineHandles.DrawBones(transform, skeleton);
if (showConstraints) SpineHandles.DrawConstraints(transform, skeleton);
if (showBoneNames) SpineHandles.DrawBoneNames(transform, skeleton);
if (showShapes) SpineHandles.DrawBoundingBoxes(transform, skeleton);
}
override public void OnInspectorGUI () {

View File

@ -50,11 +50,22 @@ namespace Spine.Unity.Editor {
public abstract class SpineTreeItemDrawerBase<T> : PropertyDrawer where T:SpineAttributeBase {
protected SkeletonDataAsset skeletonDataAsset;
internal const string NoneLabel = "<None>";
internal const string NoneString = "<None>";
// Analysis disable once StaticFieldInGenericType
static GUIContent noneLabel;
static GUIContent NoneLabel (Texture2D image = null) {
if (noneLabel == null)
noneLabel = new GUIContent(NoneString);
noneLabel.image = image;
return noneLabel;
}
protected T TargetAttribute { get { return (T)attribute; } }
protected SerializedProperty SerializedProperty { get; private set; }
protected abstract Texture2D Icon { get; }
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
SerializedProperty = property;
@ -89,11 +100,10 @@ namespace Spine.Unity.Editor {
}
position = EditorGUI.PrefixLabel(position, label);
var image = Icon;
var propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue;
if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel : propertyStringValue, EditorStyles.popup))
if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel(image) : SpineInspectorUtility.TempContent(propertyStringValue, image), EditorStyles.popup))
Selector(property);
}
public ISkeletonComponent GetTargetSkeletonComponent (SerializedProperty property) {
@ -138,6 +148,8 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineSlot))]
public class SpineSlotDrawer : SpineTreeItemDrawerBase<SpineSlot> {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.slot; } }
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSlot targetAttribute, SkeletonData data) {
for (int i = 0; i < data.Slots.Count; i++) {
string name = data.Slots.Items[i].Name;
@ -177,6 +189,8 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineSkin))]
public class SpineSkinDrawer : SpineTreeItemDrawerBase<SpineSkin> {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.skin; } }
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSkin targetAttribute, SkeletonData data) {
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
menu.AddSeparator("");
@ -192,11 +206,14 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineAnimation))]
public class SpineAnimationDrawer : SpineTreeItemDrawerBase<SpineAnimation> {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.animation; } }
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineAnimation targetAttribute, SkeletonData data) {
var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations;
// <None> item
menu.AddItem(new GUIContent(NoneLabel), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair("", property));
menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property));
for (int i = 0; i < animations.Count; i++) {
string name = animations.Items[i].Name;
@ -209,11 +226,14 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineEvent))]
public class SpineEventNameDrawer : SpineTreeItemDrawerBase<SpineEvent> {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.userEvent; } }
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineEvent targetAttribute, SkeletonData data) {
var events = skeletonDataAsset.GetSkeletonData(false).Events;
// <None> item
menu.AddItem(new GUIContent(NoneLabel), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair("", property));
menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property));
for (int i = 0; i < events.Count; i++) {
string name = events.Items[i].Name;
@ -226,6 +246,9 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineAttachment))]
public class SpineAttachmentDrawer : SpineTreeItemDrawerBase<SpineAttachment> {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.genericAttachment; } }
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineAttachment targetAttribute, SkeletonData data) {
ISkeletonComponent skeletonComponent = GetTargetSkeletonComponent(property);
var validSkins = new List<Skin>();
@ -252,7 +275,8 @@ namespace Spine.Unity.Editor {
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
menu.AddSeparator("");
menu.AddItem(new GUIContent("Null"), property.stringValue == "", HandleSelect, new SpineDrawerValuePair("", property));
const string NullAttachmentName = "";
menu.AddItem(new GUIContent("Null"), property.stringValue == NullAttachmentName, HandleSelect, new SpineDrawerValuePair(NullAttachmentName, property));
menu.AddSeparator("");
Skin defaultSkin = data.Skins.Items[0];
@ -260,9 +284,8 @@ namespace Spine.Unity.Editor {
SerializedProperty slotProperty = property.serializedObject.FindProperty(targetAttribute.slotField);
string slotMatch = "";
if (slotProperty != null) {
if (slotProperty.propertyType == SerializedPropertyType.String) {
if (slotProperty.propertyType == SerializedPropertyType.String)
slotMatch = slotProperty.stringValue.ToLower();
}
}
foreach (Skin skin in validSkins) {
@ -307,10 +330,15 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineBone))]
public class SpineBoneDrawer : SpineTreeItemDrawerBase<SpineBone> {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.bone; } }
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) {
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
menu.AddSeparator("");
menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property));
for (int i = 0; i < data.Bones.Count; i++) {
string name = data.Bones.Items[i].Name;
if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal))

View File

@ -59,6 +59,7 @@ namespace Spine.Unity.Editor {
public static Texture2D slotRoot;
public static Texture2D skinPlaceholder;
public static Texture2D image;
public static Texture2D genericAttachment;
public static Texture2D boundingBox;
public static Texture2D mesh;
public static Texture2D weights;
@ -90,11 +91,13 @@ namespace Spine.Unity.Editor {
slot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slot.png");
slotRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slotRoot.png");
skinPlaceholder = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
genericAttachment = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-attachment.png");
image = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-image.png");
boundingBox = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boundingBox.png");
mesh = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-mesh.png");
weights = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-weights.png");
skin = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
skin = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skin.png");
skinsRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinsRoot.png");
animation = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-animation.png");
animationRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-animationRoot.png");
@ -1559,15 +1562,25 @@ namespace Spine.Unity.Editor {
}
static Material _boneMaterial;
public static Material BoneMaterial {
static Material BoneMaterial {
get {
if (_boneMaterial == null) {
_boneMaterial = new Material(Shader.Find("Hidden/Spine/Bones"));
_boneMaterial.SetColor("_Color", SpineHandles.BoneColor);
}
return _boneMaterial;
}
}
public static Material GetBoneMaterial () {
BoneMaterial.SetColor("_Color", SpineHandles.BoneColor);
return BoneMaterial;
}
public static Material GetBoneMaterial (Color color) {
BoneMaterial.SetColor("_Color", color);
return BoneMaterial;
}
static Material _ikMaterial;
public static Material IKMaterial {
@ -1661,7 +1674,7 @@ namespace Spine.Unity.Editor {
const float my = 1.5f;
scale.y *= (SpineHandles.handleScale + 1f) * 0.5f;
scale.y = Mathf.Clamp(scale.x, -my, my);
SpineHandles.BoneMaterial.SetPass(0);
SpineHandles.GetBoneMaterial().SetPass(0);
Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
} else {
var wp = transform.TransformPoint(pos);
@ -1669,6 +1682,23 @@ namespace Spine.Unity.Editor {
}
}
public static void DrawBone (Transform transform, Bone b, float boneScale, Color color) {
var pos = new Vector3(b.WorldX, b.WorldY, 0);
float length = b.Data.Length;
if (length > 0) {
Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
Vector3 scale = Vector3.one * length * b.WorldScaleX;
const float my = 1.5f;
scale.y *= (SpineHandles.handleScale + 1f) * 0.5f;
scale.y = Mathf.Clamp(scale.x, -my, my);
SpineHandles.GetBoneMaterial(color).SetPass(0);
Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
} else {
var wp = transform.TransformPoint(pos);
DrawBoneCircle(wp, color, transform.forward, boneScale);
}
}
public static void DrawPaths (Transform transform, Skeleton skeleton) {
foreach (Slot s in skeleton.DrawOrder) {
var p = s.Attachment as PathAttachment;

View File

@ -48,25 +48,37 @@ namespace Spine.Unity.Editor {
get { return "\u2014"; }
}
static GUIContent tempContent;
internal static GUIContent TempContent (string text, Texture2D image = null, string tooltip = null) {
if (tempContent == null) tempContent = new GUIContent();
tempContent.text = text;
tempContent.image = image;
tempContent.tooltip = tooltip;
return tempContent;
}
public static void PropertyFieldWideLabel (SerializedProperty property, GUIContent label = null, float minimumLabelWidth = 150) {
EditorGUIUtility.labelWidth = minimumLabelWidth;
EditorGUILayout.PropertyField(property, label ?? new GUIContent(property.displayName, property.tooltip));
EditorGUILayout.PropertyField(property, label ?? TempContent(property.displayName, null, property.tooltip));
EditorGUIUtility.labelWidth = 0; // Resets to default
}
public static void PropertyFieldFitLabel (SerializedProperty property, GUIContent label = null, float extraSpace = 5f) {
label = label ?? new GUIContent(property.displayName, property.tooltip);
float width = GUI.skin.label.CalcSize(new GUIContent(label.text)).x + extraSpace;
label = label ?? TempContent(property.displayName, null, property.tooltip);
float width = GUI.skin.label.CalcSize(TempContent(label.text)).x + extraSpace;
if (label.image != null)
width += EditorGUIUtility.singleLineHeight;
PropertyFieldWideLabel(property, label, width);
}
public static bool UndoRedoPerformed (UnityEngine.Event current) {
return current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed";
}
public static Texture2D UnityIcon (System.Type type) {
return EditorGUIUtility.ObjectContent(null, type).image as Texture2D;
}
#region Layout Scopes
static GUIStyle grayMiniLabel;
public static GUIStyle GrayMiniLabel {

View File

@ -136,7 +136,7 @@ namespace Spine.Unity.Editor {
_customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides);
_customSlotMaterialsPrev = CopyList(componentCustomSlotMaterials);
if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Clear and Reapply Changes", "Removes all non-serialized overrides in the SkeletonRenderer and reapplies the overrides on this component."))) {
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Clear and Reapply Changes", tooltip: "Removes all non-serialized overrides in the SkeletonRenderer and reapplies the overrides on this component."))) {
if (skeletonRenderer != null) {
#if SPINE_OPTIONAL_MATERIALOVERRIDE
skeletonRenderer.CustomMaterialOverride.Clear();

View File

@ -84,7 +84,7 @@ namespace Spine.Unity.Editor {
return;
}
using (new SpineInspectorUtility.BoxScope()) {
EditorGUILayout.PropertyField(meshGeneratorSettings_, new GUIContent("Advanced..."), includeChildren: true);
EditorGUILayout.PropertyField(meshGeneratorSettings_, SpineInspectorUtility.TempContent("Advanced..."), includeChildren: true);
}
EditorGUILayout.Space();
@ -94,7 +94,7 @@ namespace Spine.Unity.Editor {
EditorGUILayout.PropertyField(startingAnimation_);
EditorGUILayout.PropertyField(startingLoop_);
EditorGUILayout.PropertyField(timeScale_);
EditorGUILayout.PropertyField(unscaledTime_, new GUIContent(unscaledTime_.displayName, "If checked, this will use Time.unscaledDeltaTime to make this update independent of game Time.timeScale. Instance SkeletonGraphic.timeScale will still be applied."));
EditorGUILayout.PropertyField(unscaledTime_, SpineInspectorUtility.TempContent(unscaledTime_.displayName, tooltip: "If checked, this will use Time.unscaledDeltaTime to make this update independent of game Time.timeScale. Instance SkeletonGraphic.timeScale will still be applied."));
EditorGUILayout.Space();
EditorGUILayout.PropertyField(freeze_);
EditorGUILayout.Space();

View File

@ -43,6 +43,13 @@ namespace Spine.Unity.Modules {
public override void OnInspectorGUI () {
SpineInspectorUtility.SortingPropertyFields(sortingProperties, true);
EditorGUILayout.Space();
if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Select SkeletonRenderer", SpineEditorUtilities.Icons.spine))) {
var thisSkeletonPartsRenderer = target as SkeletonPartsRenderer;
var srs = thisSkeletonPartsRenderer.GetComponentInParent<SkeletonRenderSeparator>();
if (srs != null && srs.partsRenderers.Contains(thisSkeletonPartsRenderer) && srs.SkeletonRenderer != null)
Selection.activeGameObject = srs.SkeletonRenderer.gameObject;
}
}
}

View File

@ -85,6 +85,8 @@ namespace Spine.Unity.Modules {
bool checkBox = EditorGUILayout.Toggle("Enable Separator", componentEnabled);
if (checkBox != componentEnabled)
component.enabled = checkBox;
if (component.SkeletonRenderer.disableRenderingOnOverride && !component.enabled)
EditorGUILayout.HelpBox("By default, SkeletonRenderer's MeshRenderer is disabled while the SkeletonRenderSeparator takes over rendering. It is re-enabled when SkeletonRenderSeparator is disabled.", MessageType.Info);
EditorGUILayout.PropertyField(copyPropertyBlock_);
EditorGUILayout.PropertyField(copyMeshRendererFlags_);

View File

@ -58,9 +58,9 @@ namespace Spine.Unity.Modules {
}
MeshRenderer mainMeshRenderer;
public bool copyPropertyBlock = false;
public bool copyPropertyBlock = true;
[Tooltip("Copies MeshRenderer flags into each parts renderer")]
public bool copyMeshRendererFlags = false;
public bool copyMeshRendererFlags = true;
public List<Spine.Unity.Modules.SkeletonPartsRenderer> partsRenderers = new List<SkeletonPartsRenderer>();
#if UNITY_EDITOR
@ -117,6 +117,13 @@ namespace Spine.Unity.Modules {
var lightProbeUsage = mainMeshRenderer.lightProbeUsage;
bool receiveShadows = mainMeshRenderer.receiveShadows;
#if UNITY_5_5_OR_NEWER
var reflectionProbeUsage = mainMeshRenderer.reflectionProbeUsage;
var shadowCastingMode = mainMeshRenderer.shadowCastingMode;
var motionVectorGenerationMode = mainMeshRenderer.motionVectorGenerationMode;
var probeAnchor = mainMeshRenderer.probeAnchor;
#endif
for (int i = 0; i < partsRenderers.Count; i++) {
var currentRenderer = partsRenderers[i];
if (currentRenderer == null) continue; // skip null items.
@ -124,6 +131,13 @@ namespace Spine.Unity.Modules {
var mr = currentRenderer.MeshRenderer;
mr.lightProbeUsage = lightProbeUsage;
mr.receiveShadows = receiveShadows;
#if UNITY_5_5_OR_NEWER
mr.reflectionProbeUsage = reflectionProbeUsage;
mr.shadowCastingMode = shadowCastingMode;
mr.motionVectorGenerationMode = motionVectorGenerationMode;
mr.probeAnchor = probeAnchor;
#endif
}
}
#else

View File

@ -164,11 +164,11 @@ namespace Spine.Unity.Editor {
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || utilityBone.bone.Children.Count == 0)) {
if (GUILayout.Button(new GUIContent("Add Child", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24)))
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Child", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24)))
BoneSelectorContextMenu("", utilityBone.bone.Children, "<Recursively>", SpawnChildBoneSelected);
}
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || containsOverrides)) {
if (GUILayout.Button(new GUIContent("Add Override", Icons.poseBones), GUILayout.MinWidth(120), GUILayout.Height(24)))
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Override", Icons.poseBones), GUILayout.MinWidth(120), GUILayout.Height(24)))
SpawnOverride();
}
EditorGUILayout.Space();
@ -177,14 +177,14 @@ namespace Spine.Unity.Editor {
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || !canCreateHingeChain)) {
if (GUILayout.Button(new GUIContent("Create Hinge Chain", Icons.hingeChain), GUILayout.Width(150), GUILayout.Height(24)))
if (GUILayout.Button(SpineInspectorUtility.TempContent("Create Hinge Chain", Icons.hingeChain), GUILayout.Width(150), GUILayout.Height(24)))
CreateHingeChain();
}
EditorGUILayout.Space();
}
using (new EditorGUI.DisabledGroupScope(multiObject || boundingBoxTable.Count == 0)) {
EditorGUILayout.LabelField(new GUIContent("Bounding Boxes", Icons.boundingBox), EditorStyles.boldLabel);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bounding Boxes", Icons.boundingBox), EditorStyles.boldLabel);
foreach (var entry in boundingBoxTable){
Slot slot = entry.Key;

View File

@ -31,9 +31,12 @@
// Contributed by: Mitch Thompson
using UnityEngine;
using System;
using System.Collections;
namespace Spine.Unity {
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public abstract class SpineAttributeBase : PropertyAttribute {
public string dataField = "";
public string startsWith = "";