mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-05 10:16:54 +08:00
Merge branch 'dev' into spine-c-3.5
This commit is contained in:
commit
f5b2c87cbc
@ -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]]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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("");
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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_;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user