Merge branch 'dev' into spine-c-3.5

This commit is contained in:
badlogic 2016-10-19 14:36:26 +02:00
commit f5b2c87cbc
13 changed files with 309 additions and 134 deletions

View File

@ -199,6 +199,7 @@ static void _sortPathConstraintAttachmentBones(_spSkeleton* const internal, spAt
int i = 0, n; int i = 0, n;
while (i < pathBonesCount) { while (i < pathBonesCount) {
int boneCount = pathBones[i++]; int boneCount = pathBones[i++];
int n;
for (n = i + boneCount; i < n; i++) for (n = i + boneCount; i < n; i++)
_sortBone(internal, bones[pathBones[i]]); _sortBone(internal, bones[pathBones[i]]);
} }

View File

@ -153,28 +153,25 @@ public class Bone implements Updatable {
break; break;
} }
case noRotationOrReflection: { case noRotationOrReflection: {
float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, prx; float s = pa * pa + pc * pc, prx;
if (psx > 0.0001f) { if (s > 0.0001f) {
psy = Math.abs((pa * pd - pb * pc) / psx); s = Math.abs(pa * pd - pb * pc) / s;
pb = pc * s;
pd = pa * s;
prx = atan2(pc, pa) * radDeg; prx = atan2(pc, pa) * radDeg;
} else { } else {
psx = 0; pa = 0;
psy = (float)Math.sqrt(pb * pb + pd * pd); pc = 0;
prx = 90 - atan2(pd, pb) * radDeg; 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 rx = rotation + shearX - prx;
float ry = rotation + shearY - prx + 90; float ry = rotation + shearY - prx + 90;
float la = cosDeg(rx) * scaleX; float la = cosDeg(rx) * scaleX;
float lb = cosDeg(ry) * scaleY; float lb = cosDeg(ry) * scaleY;
float lc = sinDeg(rx) * scaleX; float lc = sinDeg(rx) * scaleX;
float ld = sinDeg(ry) * scaleY; float ld = sinDeg(ry) * scaleY;
a = pa * la + pb * lc; a = pa * la - pb * lc;
b = pa * lb + pb * ld; b = pa * lb - pb * ld;
c = pc * la + pd * lc; c = pc * la + pd * lc;
d = pc * lb + pd * ld; d = pc * lb + pd * ld;
break; break;

View File

@ -447,6 +447,7 @@ public class SkeletonViewer extends ApplicationAdapter {
table.add(new Label("", skin, "default", Color.LIGHT_GRAY)); // Version. table.add(new Label("", skin, "default", Color.LIGHT_GRAY)); // Version.
} }
// Events.
window.addListener(new InputListener() { window.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
event.cancel(); event.cancel();

View File

@ -563,7 +563,7 @@ function SkeletonJson.new (attachmentLoader)
end end
local frameIndex = 0 local frameIndex = 0
for i,valueMap in ipairs(values) do 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) readCurve(valueMap, timeline, frameIndex)
frameIndex = frameIndex + 1 frameIndex = frameIndex + 1
end end

View File

@ -38,14 +38,14 @@ namespace Spine.Unity {
public class AtlasAsset : ScriptableObject { public class AtlasAsset : ScriptableObject {
public TextAsset atlasFile; public TextAsset atlasFile;
public Material[] materials; public Material[] materials;
private Atlas atlas; protected Atlas atlas;
public void Reset () { public virtual void Reset () {
atlas = null; atlas = null;
} }
/// <returns>The atlas or null if it could not be loaded.</returns> /// <returns>The atlas or null if it could not be loaded.</returns>
public Atlas GetAtlas () { public virtual Atlas GetAtlas () {
if (atlasFile == null) { if (atlasFile == null) {
Debug.LogError("Atlas file not set for atlas asset: " + name, this); Debug.LogError("Atlas file not set for atlas asset: " + name, this);
Reset(); Reset();

View File

@ -35,9 +35,11 @@ using Spine;
namespace Spine.Unity.Editor { namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonAnimation))] [CustomEditor(typeof(SkeletonAnimation))]
[CanEditMultipleObjects]
public class SkeletonAnimationInspector : SkeletonRendererInspector { public class SkeletonAnimationInspector : SkeletonRendererInspector {
protected SerializedProperty animationName, loop, timeScale, autoReset; protected SerializedProperty animationName, loop, timeScale, autoReset;
protected bool wasAnimationNameChanged; protected bool wasAnimationNameChanged;
protected bool requireRepaint;
protected override void OnEnable () { protected override void OnEnable () {
base.OnEnable(); base.OnEnable();
@ -46,64 +48,93 @@ namespace Spine.Unity.Editor {
timeScale = serializedObject.FindProperty("timeScale"); timeScale = serializedObject.FindProperty("timeScale");
} }
protected override void DrawInspectorGUI () { protected override void DrawInspectorGUI (bool multi) {
base.DrawInspectorGUI(); base.DrawInspectorGUI(multi);
if (!TargetIsValid) return;
bool sameData = SpineInspectorUtility.TargetsUseSameData(serializedObject);
SkeletonAnimation component = (SkeletonAnimation)target; // Try to reflect the animation name on the scene object.
if (!component.valid) {
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; return;
if (!isInspectingPrefab) { if (!isInspectingPrefab) {
if (wasAnimationNameChanged) { if (wasAnimationNameChanged) {
if (!Application.isPlaying) { if (!Application.isPlaying) {
if (component.state != null) component.state.ClearTrack(0); if (skeletonAnimation.state != null) skeletonAnimation.state.ClearTrack(0);
component.skeleton.SetToSetupPose(); 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 (!Application.isPlaying) {
if (animationToUse != null) animationToUse.Apply(component.skeleton, 0f, 0f, false, null); if (animationToUse != null) animationToUse.Apply(skeletonAnimation.skeleton, 0f, 0f, false, null);
component.Update(); skeletonAnimation.Update();
component.LateUpdate(); skeletonAnimation.LateUpdate();
SceneView.RepaintAll(); requireRepaint = true;
} else { } else {
if (animationToUse != null) if (animationToUse != null)
component.state.SetAnimation(0, animationToUse, loop.boolValue); skeletonAnimation.state.SetAnimation(0, animationToUse, loop.boolValue);
else else
component.state.ClearTrack(0); skeletonAnimation.state.ClearTrack(0);
} }
wasAnimationNameChanged = false; wasAnimationNameChanged = false;
} }
// Reflect animationName serialized property in the inspector even if SetAnimation API was used. // Reflect animationName serialized property in the inspector even if SetAnimation API was used.
if (Application.isPlaying) { bool multi = animationName.serializedObject.isEditingMultipleObjects;
TrackEntry current = component.state.GetCurrent(0); if (!multi && Application.isPlaying) {
TrackEntry current = skeletonAnimation.state.GetCurrent(0);
if (current != null) { if (current != null) {
if (component.AnimationName != animationName.stringValue) if (skeletonAnimation.AnimationName != animationName.stringValue)
animationName.stringValue = current.Animation.Name; 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<SkeletonUtility>() == null) {
if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30)))
component.gameObject.AddComponent<SkeletonUtility>();
}
}
} }
} }
} }

View File

@ -31,10 +31,10 @@
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using UnityEditor; using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor { namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonAnimator))] [CustomEditor(typeof(SkeletonAnimator))]
[CanEditMultipleObjects]
public class SkeletonAnimatorInspector : SkeletonRendererInspector { public class SkeletonAnimatorInspector : SkeletonRendererInspector {
protected SerializedProperty layerMixModes; protected SerializedProperty layerMixModes;
protected override void OnEnable () { protected override void OnEnable () {
@ -42,22 +42,14 @@ namespace Spine.Unity.Editor {
layerMixModes = serializedObject.FindProperty("layerMixModes"); layerMixModes = serializedObject.FindProperty("layerMixModes");
} }
protected override void DrawInspectorGUI () { protected override void DrawInspectorGUI (bool multi) {
base.DrawInspectorGUI(); base.DrawInspectorGUI(multi);
EditorGUILayout.PropertyField(layerMixModes, true); EditorGUILayout.PropertyField(layerMixModes, true);
var component = (SkeletonAnimator)target;
if (!component.valid)
return;
EditorGUILayout.Space(); if (!TargetIsValid) return;
if (!isInspectingPrefab) { if (!isInspectingPrefab)
if (component.GetComponent<SkeletonUtility>() == null) { DrawSkeletonUtilityButton(multi);
if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))) {
component.gameObject.AddComponent<SkeletonUtility>();
}
}
}
} }
} }
} }

View File

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

View File

@ -53,8 +53,11 @@ namespace Spine.Unity.Editor {
internal const string NoneLabel = "<None>"; internal const string NoneLabel = "<None>";
protected T TargetAttribute { get { return (T)attribute; } } protected T TargetAttribute { get { return (T)attribute; } }
protected SerializedProperty SerializedProperty { get; private set; }
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) { public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
SerializedProperty = property;
if (property.propertyType != SerializedPropertyType.String) { if (property.propertyType != SerializedPropertyType.String) {
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
return; return;
@ -87,7 +90,7 @@ namespace Spine.Unity.Editor {
position = EditorGUI.PrefixLabel(position, label); 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)) if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel : propertyStringValue, EditorStyles.popup))
Selector(property); Selector(property);
@ -302,7 +305,6 @@ namespace Spine.Unity.Editor {
[CustomPropertyDrawer(typeof(SpineBone))] [CustomPropertyDrawer(typeof(SpineBone))]
public class SpineBoneDrawer : SpineTreeItemDrawerBase<SpineBone> { public class SpineBoneDrawer : SpineTreeItemDrawerBase<SpineBone> {
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) { protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) {
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
menu.AddSeparator(""); menu.AddSeparator("");

View File

@ -1162,7 +1162,7 @@ namespace Spine.Unity.Editor {
var skeletonInfo = (Dictionary<string, object>)root["skeleton"]; var skeletonInfo = (Dictionary<string, object>)root["skeleton"];
object jv; object jv;
skeletonInfo.TryGetValue("spine", out jv); skeletonInfo.TryGetValue("spine", out jv);
string jsonVersion = (jv == null) ? (string)jv : null; string jsonVersion = jv as string;
if (!string.IsNullOrEmpty(jsonVersion)) { if (!string.IsNullOrEmpty(jsonVersion)) {
string[] jsonVersionSplit = jsonVersion.Split('.'); string[] jsonVersionSplit = jsonVersion.Split('.');
bool match = false; bool match = false;

View File

@ -30,6 +30,7 @@
using UnityEngine; using UnityEngine;
using UnityEditor; using UnityEditor;
using System.Collections.Generic;
using System.Reflection; using System.Reflection;
namespace Spine.Unity.Editor { namespace Spine.Unity.Editor {
@ -43,6 +44,10 @@ namespace Spine.Unity.Editor {
return n == 1 ? "" : "s"; return n == 1 ? "" : "s";
} }
public static string EmDash {
get { return "\u2014"; }
}
public static void PropertyFieldWideLabel (SerializedProperty property, GUIContent label = null, float minimumLabelWidth = 150) { public static void PropertyFieldWideLabel (SerializedProperty property, GUIContent label = null, float minimumLabelWidth = 150) {
using (new EditorGUILayout.HorizontalScope()) { using (new EditorGUILayout.HorizontalScope()) {
GUILayout.Label(label ?? new GUIContent(property.displayName, property.tooltip), GUILayout.MinWidth(minimumLabelWidth)); 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 sortingLayerID;
public SerializedProperty sortingOrder; public SerializedProperty sortingOrder;
public SerializedSortingProperties (Renderer r) { public SerializedSortingProperties (Renderer r) : this(new SerializedObject(r)) {}
renderer = new SerializedObject(r); public SerializedSortingProperties (Object[] renderers) : this(new SerializedObject(renderers)) {}
public SerializedSortingProperties (SerializedObject rendererSerializedObject) {
renderer = rendererSerializedObject;
sortingLayerID = renderer.FindProperty("m_SortingLayerID"); sortingLayerID = renderer.FindProperty("m_SortingLayerID");
sortingOrder = renderer.FindProperty("m_SortingOrder"); sortingOrder = renderer.FindProperty("m_SortingOrder");
} }
public void ApplyModifiedProperties () { public void ApplyModifiedProperties () {
renderer.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<Object>();
foreach (var o in serializedObject.targetObjects) {
var component = o as Component;
if (component != null) {
var renderer = component.GetComponent<Renderer>();
if (renderer != null)
renderers.Add(renderer);
}
}
return new SerializedObject(renderers.ToArray());
} else {
var component = serializedObject.targetObject as Component;
if (component != null) {
var renderer = component.GetComponent<Renderer>();
if (renderer != null)
return new SerializedObject(renderer);
}
}
return null;
}
public static bool TargetsUseSameData (SerializedObject so) {
bool multi = so.isEditingMultipleObjects;
if (multi) {
int n = so.targetObjects.Length;
var first = so.targetObjects[0] as SkeletonRenderer;
for (int i = 1; i < n; i++) {
var sr = so.targetObjects[i] as SkeletonRenderer;
if (sr != null && sr.skeletonDataAsset != first.skeletonDataAsset)
return false;
}
}
return true;
} }
public static void SortingPropertyFields (SerializedSortingProperties prop, bool applyModifiedProperties) { public static void SortingPropertyFields (SerializedSortingProperties prop, bool applyModifiedProperties) {
if (applyModifiedProperties) { if (applyModifiedProperties) {
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder); SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder);
if(EditorGUI.EndChangeCheck()) { if(EditorGUI.EndChangeCheck())
prop.ApplyModifiedProperties(); prop.ApplyModifiedProperties();
EditorUtility.SetDirty(prop.renderer.targetObject);
}
} else { } else {
SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder); SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder);
} }

View File

@ -40,6 +40,7 @@ namespace Spine.Unity.Editor {
[InitializeOnLoad] [InitializeOnLoad]
[CustomEditor(typeof(SkeletonGraphic))] [CustomEditor(typeof(SkeletonGraphic))]
[CanEditMultipleObjects]
public class SkeletonGraphicInspector : UnityEditor.Editor { public class SkeletonGraphicInspector : UnityEditor.Editor {
SerializedProperty material_, color_; SerializedProperty material_, color_;
SerializedProperty skeletonDataAsset_, initialSkinName_; SerializedProperty skeletonDataAsset_, initialSkinName_;

View File

@ -114,6 +114,8 @@ namespace Spine.Unity.Editor {
skeleton = skeletonRenderer.skeleton; skeleton = skeletonRenderer.skeleton;
} }
if (!skeletonRenderer.valid) return;
UpdateAttachments(); UpdateAttachments();
isPrefab |= PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab; isPrefab |= PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab;
} }
@ -142,7 +144,6 @@ namespace Spine.Unity.Editor {
void UpdateAttachments () { void UpdateAttachments () {
attachmentTable = new Dictionary<Slot, List<Attachment>>(); attachmentTable = new Dictionary<Slot, List<Attachment>>();
Skin skin = skeleton.Skin ?? skeletonRenderer.skeletonDataAsset.GetSkeletonData(true).DefaultSkin; Skin skin = skeleton.Skin ?? skeletonRenderer.skeletonDataAsset.GetSkeletonData(true).DefaultSkin;
for (int i = skeleton.Slots.Count-1; i >= 0; i--) { for (int i = skeleton.Slots.Count-1; i >= 0; i--) {
List<Attachment> attachments = new List<Attachment>(); List<Attachment> attachments = new List<Attachment>();
@ -176,20 +177,22 @@ namespace Spine.Unity.Editor {
return; return;
} }
if (!skeletonRenderer.valid) {
GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", SpineEditorUtilities.Icons.warning));
return;
}
skeletonUtility.boneRoot = (Transform)EditorGUILayout.ObjectField("Bone Root", skeletonUtility.boneRoot, typeof(Transform), true); skeletonUtility.boneRoot = (Transform)EditorGUILayout.ObjectField("Bone Root", skeletonUtility.boneRoot, typeof(Transform), true);
GUILayout.BeginHorizontal(); using (new GUILayout.HorizontalScope()) {
EditorGUI.BeginDisabledGroup(skeletonUtility.boneRoot != null); using (new EditorGUI.DisabledGroupScope(skeletonUtility.boneRoot != null)) {
{ if (GUILayout.Button(new GUIContent("Spawn Hierarchy", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(150), GUILayout.Height(24)))
if (GUILayout.Button(new GUIContent("Spawn Hierarchy", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(150), GUILayout.Height(24))) SpawnHierarchyContextMenu();
SpawnHierarchyContextMenu(); }
// if (GUILayout.Button(new GUIContent("Spawn Submeshes", SpineEditorUtilities.Icons.subMeshRenderer), GUILayout.Width(150), GUILayout.Height(24)))
// skeletonUtility.SpawnSubRenderers(true);
} }
EditorGUI.EndDisabledGroup();
// if (GUILayout.Button(new GUIContent("Spawn Submeshes", SpineEditorUtilities.Icons.subMeshRenderer), GUILayout.Width(150), GUILayout.Height(24)))
// skeletonUtility.SpawnSubRenderers(true);
GUILayout.EndHorizontal();
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
skeleton.FlipX = EditorGUILayout.ToggleLeft("Flip X", skeleton.FlipX); skeleton.FlipX = EditorGUILayout.ToggleLeft("Flip X", skeleton.FlipX);