diff --git a/spine-c/src/spine/Skeleton.c b/spine-c/src/spine/Skeleton.c
index a193d2bf7..4af6db685 100644
--- a/spine-c/src/spine/Skeleton.c
+++ b/spine-c/src/spine/Skeleton.c
@@ -188,7 +188,8 @@ static void _sortPathConstraintAttachmentBones(_spSkeleton* const internal, spAt
int i = 0;
while (i < pathBonesCount) {
int boneCount = pathBones[i++];
- for (int n = i + boneCount; i < n; i++)
+ int n;
+ for (n = i + boneCount; i < n; i++)
_sortBone(internal, bones[pathBones[i]]);
}
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java
index 3b3d451a1..98e398107 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java
@@ -153,28 +153,25 @@ public class Bone implements Updatable {
break;
}
case noRotationOrReflection: {
- float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, prx;
- if (psx > 0.0001f) {
- psy = Math.abs((pa * pd - pb * pc) / psx);
+ float s = pa * pa + pc * pc, prx;
+ if (s > 0.0001f) {
+ s = Math.abs(pa * pd - pb * pc) / s;
+ pb = pc * s;
+ pd = pa * s;
prx = atan2(pc, pa) * radDeg;
} else {
- psx = 0;
- psy = (float)Math.sqrt(pb * pb + pd * pd);
+ pa = 0;
+ pc = 0;
prx = 90 - atan2(pd, pb) * radDeg;
}
- float cos = cosDeg(prx), sin = sinDeg(prx);
- pa = cos * psx;
- pb = -sin * psy;
- pc = sin * psx;
- pd = cos * psy;
float rx = rotation + shearX - prx;
float ry = rotation + shearY - prx + 90;
float la = cosDeg(rx) * scaleX;
float lb = cosDeg(ry) * scaleY;
float lc = sinDeg(rx) * scaleX;
float ld = sinDeg(ry) * scaleY;
- a = pa * la + pb * lc;
- b = pa * lb + pb * ld;
+ a = pa * la - pb * lc;
+ b = pa * lb - pb * ld;
c = pc * la + pd * lc;
d = pc * lb + pd * ld;
break;
diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java
index 63cadcfe2..34a8c6245 100644
--- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java
+++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java
@@ -430,7 +430,7 @@ public class SkeletonViewer extends ApplicationAdapter {
stage.addActor(window);
{
- Table table = new Table(skin);
+ Table table = new Table();
table.setFillParent(true);
table.setTouchable(Touchable.disabled);
stage.addActor(table);
@@ -438,6 +438,16 @@ public class SkeletonViewer extends ApplicationAdapter {
table.add(toasts);
}
+ {
+ Table table = new Table();
+ table.setFillParent(true);
+ table.setTouchable(Touchable.disabled);
+ stage.addActor(table);
+ table.pad(10).top().right();
+ table.add(new Label("", skin, "default", Color.LIGHT_GRAY)); // Version.
+ }
+
+ // Events.
window.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
event.cancel();
diff --git a/spine-lua/SkeletonJson.lua b/spine-lua/SkeletonJson.lua
index 697fec741..16c2cf10c 100644
--- a/spine-lua/SkeletonJson.lua
+++ b/spine-lua/SkeletonJson.lua
@@ -563,7 +563,7 @@ function SkeletonJson.new (attachmentLoader)
end
local frameIndex = 0
for i,valueMap in ipairs(values) do
- timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1), getValue(valueMap, "scaleMix", 1) getValue(valueMap, "shearMix", 1))
+ timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1), getValue(valueMap, "scaleMix", 1), getValue(valueMap, "shearMix", 1))
readCurve(valueMap, timeline, frameIndex)
frameIndex = frameIndex + 1
end
diff --git a/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs b/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs
index 07daab329..e66986163 100644
--- a/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs
+++ b/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs
@@ -38,14 +38,14 @@ namespace Spine.Unity {
public class AtlasAsset : ScriptableObject {
public TextAsset atlasFile;
public Material[] materials;
- private Atlas atlas;
+ protected Atlas atlas;
- public void Reset () {
+ public virtual void Reset () {
atlas = null;
}
/// The atlas or null if it could not be loaded.
- public Atlas GetAtlas () {
+ public virtual Atlas GetAtlas () {
if (atlasFile == null) {
Debug.LogError("Atlas file not set for atlas asset: " + name, this);
Reset();
diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs
index 6c5faac14..f79c67ed6 100644
--- a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs
@@ -35,9 +35,11 @@ using Spine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonAnimation))]
+ [CanEditMultipleObjects]
public class SkeletonAnimationInspector : SkeletonRendererInspector {
protected SerializedProperty animationName, loop, timeScale, autoReset;
protected bool wasAnimationNameChanged;
+ protected bool requireRepaint;
protected override void OnEnable () {
base.OnEnable();
@@ -46,64 +48,93 @@ namespace Spine.Unity.Editor {
timeScale = serializedObject.FindProperty("timeScale");
}
- protected override void DrawInspectorGUI () {
- base.DrawInspectorGUI();
+ protected override void DrawInspectorGUI (bool multi) {
+ base.DrawInspectorGUI(multi);
+ if (!TargetIsValid) return;
+ bool sameData = SpineInspectorUtility.TargetsUseSameData(serializedObject);
- SkeletonAnimation component = (SkeletonAnimation)target;
- if (!component.valid)
+ // Try to reflect the animation name on the scene object.
+ {
+ if (multi)
+ foreach (var o in targets)
+ TrySetAnimation(o);
+ else
+ TrySetAnimation(target);
+ }
+
+ EditorGUILayout.Space();
+
+ if (multi && !sameData)
+ EditorGUILayout.DelayedTextField(animationName);
+ else {
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(animationName);
+ wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
+ }
+
+ EditorGUILayout.PropertyField(loop);
+
+ EditorGUILayout.PropertyField(timeScale);
+ if (multi) {
+ foreach (var o in targets) {
+ var component = o as SkeletonAnimation;
+ component.timeScale = Mathf.Max(component.timeScale, 0);
+ }
+ } else {
+ var component = (SkeletonAnimation)target;
+ component.timeScale = Mathf.Max(component.timeScale, 0);
+ }
+
+ if (!isInspectingPrefab) {
+ if (requireRepaint) {
+ SceneView.RepaintAll();
+ requireRepaint = false;
+ }
+
+ DrawSkeletonUtilityButton(multi);
+ }
+ }
+
+ protected void TrySetAnimation (Object o) {
+ var skeletonAnimation = o as SkeletonAnimation;
+ if (skeletonAnimation == null) return;
+ if (!skeletonAnimation.valid)
return;
if (!isInspectingPrefab) {
if (wasAnimationNameChanged) {
if (!Application.isPlaying) {
- if (component.state != null) component.state.ClearTrack(0);
- component.skeleton.SetToSetupPose();
+ if (skeletonAnimation.state != null) skeletonAnimation.state.ClearTrack(0);
+ skeletonAnimation.skeleton.SetToSetupPose();
}
- Spine.Animation animationToUse = component.skeleton.Data.FindAnimation(animationName.stringValue);
+ Spine.Animation animationToUse = skeletonAnimation.skeleton.Data.FindAnimation(animationName.stringValue);
if (!Application.isPlaying) {
- if (animationToUse != null) animationToUse.Apply(component.skeleton, 0f, 0f, false, null);
- component.Update();
- component.LateUpdate();
- SceneView.RepaintAll();
+ if (animationToUse != null) animationToUse.Apply(skeletonAnimation.skeleton, 0f, 0f, false, null);
+ skeletonAnimation.Update();
+ skeletonAnimation.LateUpdate();
+ requireRepaint = true;
} else {
if (animationToUse != null)
- component.state.SetAnimation(0, animationToUse, loop.boolValue);
+ skeletonAnimation.state.SetAnimation(0, animationToUse, loop.boolValue);
else
- component.state.ClearTrack(0);
+ skeletonAnimation.state.ClearTrack(0);
}
wasAnimationNameChanged = false;
}
// Reflect animationName serialized property in the inspector even if SetAnimation API was used.
- if (Application.isPlaying) {
- TrackEntry current = component.state.GetCurrent(0);
+ bool multi = animationName.serializedObject.isEditingMultipleObjects;
+ if (!multi && Application.isPlaying) {
+ TrackEntry current = skeletonAnimation.state.GetCurrent(0);
if (current != null) {
- if (component.AnimationName != animationName.stringValue)
+ if (skeletonAnimation.AnimationName != animationName.stringValue)
animationName.stringValue = current.Animation.Name;
}
}
}
-
- EditorGUILayout.Space();
- EditorGUI.BeginChangeCheck();
- EditorGUILayout.PropertyField(animationName);
- wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
-
- EditorGUILayout.PropertyField(loop);
- EditorGUILayout.PropertyField(timeScale);
- component.timeScale = Mathf.Max(component.timeScale, 0);
-
- EditorGUILayout.Space();
-
- if (!isInspectingPrefab) {
- if (component.GetComponent() == null) {
- if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30)))
- component.gameObject.AddComponent();
- }
- }
}
}
}
diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimatorInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimatorInspector.cs
index 369249e10..8204cd800 100644
--- a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimatorInspector.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimatorInspector.cs
@@ -31,10 +31,10 @@
// Contributed by: Mitch Thompson
using UnityEditor;
-using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonAnimator))]
+ [CanEditMultipleObjects]
public class SkeletonAnimatorInspector : SkeletonRendererInspector {
protected SerializedProperty layerMixModes;
protected override void OnEnable () {
@@ -42,22 +42,14 @@ namespace Spine.Unity.Editor {
layerMixModes = serializedObject.FindProperty("layerMixModes");
}
- protected override void DrawInspectorGUI () {
- base.DrawInspectorGUI();
+ protected override void DrawInspectorGUI (bool multi) {
+ base.DrawInspectorGUI(multi);
EditorGUILayout.PropertyField(layerMixModes, true);
- var component = (SkeletonAnimator)target;
- if (!component.valid)
- return;
- EditorGUILayout.Space();
+ if (!TargetIsValid) return;
- if (!isInspectingPrefab) {
- if (component.GetComponent() == null) {
- if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))) {
- component.gameObject.AddComponent();
- }
- }
- }
+ if (!isInspectingPrefab)
+ DrawSkeletonUtilityButton(multi);
}
}
}
diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs
index 37d81745f..f106870d3 100644
--- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs
@@ -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();
- 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);
}
- component.skeletonDataAsset.Reset();
}
+ }
+
+ 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();
+ 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);
+ }
+ }
+ }
+
+ 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 (meshFilter == null)
- meshFilter = component.GetComponent();
-
- 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;
+ #if NO_PREFAB_MESH
+ if (isInspectingPrefab) {
+ MeshFilter meshFilter = component.GetComponent();
+ if (meshFilter != null)
+ meshFilter.sharedMesh = null;
+ }
+ #endif
+
+ // 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() == null)
+ // component.gameObject.AddComponent();
+ // }
+ } else {
+ EditorGUILayout.Space();
+ var component = (SkeletonAnimation)target;
+ if (component.GetComponent() == null) {
+ if (GUILayout.Button(buttonContent, GUILayout.Height(30)))
+ component.gameObject.AddComponent();
+ }
+ }
+ }
+
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);
+ }
+
+ }
+
+
}
}
diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
index d773176e4..219488a91 100644
--- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
@@ -53,8 +53,11 @@ namespace Spine.Unity.Editor {
internal const string NoneLabel = "";
protected T TargetAttribute { get { return (T)attribute; } }
+ protected SerializedProperty SerializedProperty { get; private set; }
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
+ SerializedProperty = property;
+
if (property.propertyType != SerializedPropertyType.String) {
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
return;
@@ -87,7 +90,7 @@ namespace Spine.Unity.Editor {
position = EditorGUI.PrefixLabel(position, label);
- var propertyStringValue = property.stringValue;
+ var propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue;
if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel : propertyStringValue, EditorStyles.popup))
Selector(property);
@@ -302,7 +305,6 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineBone))]
public class SpineBoneDrawer : SpineTreeItemDrawerBase {
-
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) {
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
menu.AddSeparator("");
diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
index ee46f4ab9..db41f7d4b 100644
--- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
@@ -1162,7 +1162,7 @@ namespace Spine.Unity.Editor {
var skeletonInfo = (Dictionary)root["skeleton"];
object jv;
skeletonInfo.TryGetValue("spine", out jv);
- string jsonVersion = (jv == null) ? (string)jv : null;
+ string jsonVersion = jv as string;
if (!string.IsNullOrEmpty(jsonVersion)) {
string[] jsonVersionSplit = jsonVersion.Split('.');
bool match = false;
diff --git a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs
index 6839d7a37..d96e5bd1c 100644
--- a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs
@@ -30,6 +30,7 @@
using UnityEngine;
using UnityEditor;
+using System.Collections.Generic;
using System.Reflection;
namespace Spine.Unity.Editor {
@@ -43,6 +44,10 @@ namespace Spine.Unity.Editor {
return n == 1 ? "" : "s";
}
+ public static string EmDash {
+ get { return "\u2014"; }
+ }
+
public static void PropertyFieldWideLabel (SerializedProperty property, GUIContent label = null, float minimumLabelWidth = 150) {
using (new EditorGUILayout.HorizontalScope()) {
GUILayout.Label(label ?? new GUIContent(property.displayName, property.tooltip), GUILayout.MinWidth(minimumLabelWidth));
@@ -70,25 +75,72 @@ namespace Spine.Unity.Editor {
public SerializedProperty sortingLayerID;
public SerializedProperty sortingOrder;
- public SerializedSortingProperties (Renderer r) {
- renderer = new SerializedObject(r);
+ public SerializedSortingProperties (Renderer r) : this(new SerializedObject(r)) {}
+ public SerializedSortingProperties (Object[] renderers) : this(new SerializedObject(renderers)) {}
+ public SerializedSortingProperties (SerializedObject rendererSerializedObject) {
+ renderer = rendererSerializedObject;
sortingLayerID = renderer.FindProperty("m_SortingLayerID");
sortingOrder = renderer.FindProperty("m_SortingOrder");
}
public void ApplyModifiedProperties () {
renderer.ApplyModifiedProperties();
+ this.SetDirty();
}
+
+ internal void SetDirty () {
+ if (renderer.isEditingMultipleObjects)
+ foreach (var o in renderer.targetObjects)
+ EditorUtility.SetDirty(o);
+ else
+ EditorUtility.SetDirty(renderer.targetObject);
+ }
+ }
+
+ public static SerializedObject GetRenderersSerializedObject (SerializedObject serializedObject) {
+ if (serializedObject.isEditingMultipleObjects) {
+ var renderers = new List