|
@@ -31,17 +31,34 @@
|
|
|
#define NO_PREFAB_MESH
|
|
|
|
|
|
using UnityEditor;
|
|
|
+using System.Collections.Generic;
|
|
|
using UnityEngine;
|
|
|
|
|
|
namespace Spine.Unity.Editor {
|
|
|
|
|
|
[CustomEditor(typeof(SkeletonRenderer))]
|
|
|
+ [CanEditMultipleObjects]
|
|
|
public class SkeletonRendererInspector : UnityEditor.Editor {
|
|
|
protected static bool advancedFoldout;
|
|
|
protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors;
|
|
|
protected SpineInspectorUtility.SerializedSortingProperties sortingProperties;
|
|
|
protected bool isInspectingPrefab;
|
|
|
- protected MeshFilter meshFilter;
|
|
|
+
|
|
|
+ protected bool TargetIsValid {
|
|
|
+ get {
|
|
|
+ if (serializedObject.isEditingMultipleObjects) {
|
|
|
+ foreach (var o in targets) {
|
|
|
+ var component = (SkeletonRenderer)o;
|
|
|
+ if (!component.valid)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ var component = (SkeletonRenderer)target;
|
|
|
+ return component.valid;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
protected virtual void OnEnable () {
|
|
|
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
|
@@ -60,8 +77,8 @@ namespace Spine.Unity.Editor {
|
|
|
frontFacing = serializedObject.FindProperty("frontFacing");
|
|
|
zSpacing = serializedObject.FindProperty("zSpacing");
|
|
|
|
|
|
- var renderer = ((SkeletonRenderer)target).GetComponent<Renderer>();
|
|
|
- sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(renderer);
|
|
|
+ SerializedObject rso = SpineInspectorUtility.GetRenderersSerializedObject(serializedObject);
|
|
|
+ sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(rso);
|
|
|
}
|
|
|
|
|
|
public static void ReapplySeparatorSlotNames (SkeletonRenderer skeletonRenderer) {
|
|
@@ -76,62 +93,105 @@ namespace Spine.Unity.Editor {
|
|
|
var slot = skeleton.FindSlot(separatorSlotNames[i]);
|
|
|
if (slot != null) {
|
|
|
separatorSlots.Add(slot);
|
|
|
- //Debug.Log(slot + " added as separator.");
|
|
|
} else {
|
|
|
Debug.LogWarning(separatorSlotNames[i] + " is not a slot in " + skeletonRenderer.skeletonDataAsset.skeletonJSON.name);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- //Debug.Log("Reapplied Separator Slot Names. Count is now: " + separatorSlots.Count);
|
|
|
}
|
|
|
|
|
|
- protected virtual void DrawInspectorGUI () {
|
|
|
- // JOHN: todo: support multiediting.
|
|
|
- SkeletonRenderer component = (SkeletonRenderer)target;
|
|
|
-
|
|
|
- using (new EditorGUILayout.HorizontalScope()) {
|
|
|
- EditorGUILayout.PropertyField(skeletonDataAsset);
|
|
|
- const string ReloadButtonLabel = "Reload";
|
|
|
- float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20;
|
|
|
- if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) {
|
|
|
- if (component.skeletonDataAsset != null) {
|
|
|
- foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) {
|
|
|
- if (aa != null)
|
|
|
- aa.Reset();
|
|
|
+ protected virtual void DrawInspectorGUI (bool multi) {
|
|
|
+ bool valid = TargetIsValid;
|
|
|
+ if (multi) {
|
|
|
+ using (new EditorGUILayout.HorizontalScope()) {
|
|
|
+ EditorGUILayout.PropertyField(skeletonDataAsset);
|
|
|
+ const string ReloadButtonLabel = "Reload";
|
|
|
+ float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20;
|
|
|
+ if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) {
|
|
|
+ foreach (var c in targets) {
|
|
|
+ var component = c as SkeletonRenderer;
|
|
|
+ if (component.skeletonDataAsset != null) {
|
|
|
+ foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) {
|
|
|
+ if (aa != null)
|
|
|
+ aa.Reset();
|
|
|
+ }
|
|
|
+ component.skeletonDataAsset.Reset();
|
|
|
+ }
|
|
|
+ component.Initialize(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var c in targets) {
|
|
|
+ var component = c as SkeletonRenderer;
|
|
|
+ if (!component.valid) {
|
|
|
+ component.Initialize(true);
|
|
|
+ component.LateUpdate();
|
|
|
+ if (!component.valid)
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ #if NO_PREFAB_MESH
|
|
|
+ if (isInspectingPrefab) {
|
|
|
+ MeshFilter meshFilter = component.GetComponent<MeshFilter>();
|
|
|
+ if (meshFilter != null)
|
|
|
+ meshFilter.sharedMesh = null;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if (valid)
|
|
|
+ EditorGUILayout.PropertyField(initialSkinName);
|
|
|
+ } else {
|
|
|
+ var component = (SkeletonRenderer)target;
|
|
|
+
|
|
|
+ using (new EditorGUILayout.HorizontalScope()) {
|
|
|
+ EditorGUILayout.PropertyField(skeletonDataAsset);
|
|
|
+ if (valid) {
|
|
|
+ const string ReloadButtonLabel = "Reload";
|
|
|
+ float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20;
|
|
|
+ if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) {
|
|
|
+ if (component.skeletonDataAsset != null) {
|
|
|
+ foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) {
|
|
|
+ if (aa != null)
|
|
|
+ aa.Reset();
|
|
|
+ }
|
|
|
+ component.skeletonDataAsset.Reset();
|
|
|
+ }
|
|
|
+ component.Initialize(true);
|
|
|
}
|
|
|
- component.skeletonDataAsset.Reset();
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!component.valid) {
|
|
|
component.Initialize(true);
|
|
|
+ component.LateUpdate();
|
|
|
+ if (!component.valid) {
|
|
|
+ EditorGUILayout.HelpBox("Skeleton Data Asset required", MessageType.Warning);
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (!component.valid) {
|
|
|
- component.Initialize(true);
|
|
|
- component.LateUpdate();
|
|
|
- if (!component.valid)
|
|
|
- return;
|
|
|
- }
|
|
|
+ #if NO_PREFAB_MESH
|
|
|
+ if (isInspectingPrefab) {
|
|
|
+ MeshFilter meshFilter = component.GetComponent<MeshFilter>();
|
|
|
+ if (meshFilter != null)
|
|
|
+ meshFilter.sharedMesh = null;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
|
|
|
- #if NO_PREFAB_MESH
|
|
|
- if (meshFilter == null)
|
|
|
- meshFilter = component.GetComponent<MeshFilter>();
|
|
|
-
|
|
|
- if (isInspectingPrefab)
|
|
|
- meshFilter.sharedMesh = null;
|
|
|
- #endif
|
|
|
-
|
|
|
- // Initial skin name.
|
|
|
- {
|
|
|
- string[] skins = new string[component.skeleton.Data.Skins.Count];
|
|
|
- int skinIndex = 0;
|
|
|
- for (int i = 0; i < skins.Length; i++) {
|
|
|
- string skinNameString = component.skeleton.Data.Skins.Items[i].Name;
|
|
|
- skins[i] = skinNameString;
|
|
|
- if (skinNameString == initialSkinName.stringValue)
|
|
|
- skinIndex = i;
|
|
|
+ // Initial skin name.
|
|
|
+ if (valid) {
|
|
|
+ string[] skins = new string[component.skeleton.Data.Skins.Count];
|
|
|
+ int skinIndex = 0;
|
|
|
+ for (int i = 0; i < skins.Length; i++) {
|
|
|
+ string skinNameString = component.skeleton.Data.Skins.Items[i].Name;
|
|
|
+ skins[i] = skinNameString;
|
|
|
+ if (skinNameString == initialSkinName.stringValue)
|
|
|
+ skinIndex = i;
|
|
|
+ }
|
|
|
+ skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins);
|
|
|
+ initialSkinName.stringValue = skins[skinIndex];
|
|
|
}
|
|
|
- skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins);
|
|
|
- initialSkinName.stringValue = skins[skinIndex];
|
|
|
}
|
|
|
|
|
|
EditorGUILayout.Space();
|
|
@@ -139,6 +199,8 @@ namespace Spine.Unity.Editor {
|
|
|
// Sorting Layers
|
|
|
SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true);
|
|
|
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
// More Render Options...
|
|
|
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
|
|
|
EditorGUI.indentLevel++;
|
|
@@ -183,14 +245,47 @@ namespace Spine.Unity.Editor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void DrawSkeletonUtilityButton (bool multi) {
|
|
|
+ var buttonContent = new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility);
|
|
|
+ if (multi) {
|
|
|
+ // Support multi-edit SkeletonUtility button.
|
|
|
+ // EditorGUILayout.Space();
|
|
|
+ // bool addSkeletonUtility = GUILayout.Button(buttonContent, GUILayout.Height(30));
|
|
|
+ // foreach (var t in targets) {
|
|
|
+ // var component = t as SkeletonAnimation;
|
|
|
+ // if (addSkeletonUtility && component.GetComponent<SkeletonUtility>() == null)
|
|
|
+ // component.gameObject.AddComponent<SkeletonUtility>();
|
|
|
+ // }
|
|
|
+ } else {
|
|
|
+ EditorGUILayout.Space();
|
|
|
+ var component = (SkeletonAnimation)target;
|
|
|
+ if (component.GetComponent<SkeletonUtility>() == null) {
|
|
|
+ if (GUILayout.Button(buttonContent, GUILayout.Height(30)))
|
|
|
+ component.gameObject.AddComponent<SkeletonUtility>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
override public void OnInspectorGUI () {
|
|
|
//serializedObject.Update();
|
|
|
- DrawInspectorGUI();
|
|
|
+ bool multi = serializedObject.isEditingMultipleObjects;
|
|
|
+ DrawInspectorGUI(multi);
|
|
|
if (serializedObject.ApplyModifiedProperties() ||
|
|
|
(UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
|
|
|
) {
|
|
|
- if (!Application.isPlaying)
|
|
|
- ((SkeletonRenderer)target).Initialize(true);
|
|
|
+ if (!Application.isPlaying) {
|
|
|
+ if (multi) {
|
|
|
+ foreach (var o in targets) {
|
|
|
+ var sr = o as SkeletonRenderer;
|
|
|
+ sr.Initialize(true);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ((SkeletonRenderer)target).Initialize(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|