mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Importer improvements
Attributes Multiple atlas support More examples
This commit is contained in:
parent
b3b3b25a83
commit
444a536dad
@ -32,15 +32,15 @@ using System;
|
|||||||
|
|
||||||
namespace Spine {
|
namespace Spine {
|
||||||
public class AtlasAttachmentLoader : AttachmentLoader {
|
public class AtlasAttachmentLoader : AttachmentLoader {
|
||||||
private Atlas atlas;
|
private Atlas[] atlasArray;
|
||||||
|
|
||||||
public AtlasAttachmentLoader (Atlas atlas) {
|
public AtlasAttachmentLoader (params Atlas[] atlasArray) {
|
||||||
if (atlas == null) throw new ArgumentNullException("atlas cannot be null.");
|
if (atlasArray == null) throw new ArgumentNullException("atlas array cannot be null.");
|
||||||
this.atlas = atlas;
|
this.atlasArray = atlasArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) {
|
public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) {
|
||||||
AtlasRegion region = atlas.FindRegion(path);
|
AtlasRegion region = FindRegion(path);
|
||||||
if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||||
RegionAttachment attachment = new RegionAttachment(name);
|
RegionAttachment attachment = new RegionAttachment(name);
|
||||||
attachment.RendererObject = region;
|
attachment.RendererObject = region;
|
||||||
@ -55,7 +55,7 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) {
|
public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) {
|
||||||
AtlasRegion region = atlas.FindRegion(path);
|
AtlasRegion region = FindRegion(path);
|
||||||
if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||||
MeshAttachment attachment = new MeshAttachment(name);
|
MeshAttachment attachment = new MeshAttachment(name);
|
||||||
attachment.RendererObject = region;
|
attachment.RendererObject = region;
|
||||||
@ -74,7 +74,7 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path) {
|
public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path) {
|
||||||
AtlasRegion region = atlas.FindRegion(path);
|
AtlasRegion region = FindRegion(path);
|
||||||
if (region == null) throw new Exception("Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")");
|
if (region == null) throw new Exception("Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")");
|
||||||
SkinnedMeshAttachment attachment = new SkinnedMeshAttachment(name);
|
SkinnedMeshAttachment attachment = new SkinnedMeshAttachment(name);
|
||||||
attachment.RendererObject = region;
|
attachment.RendererObject = region;
|
||||||
@ -95,5 +95,17 @@ namespace Spine {
|
|||||||
public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) {
|
public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) {
|
||||||
return new BoundingBoxAttachment(name);
|
return new BoundingBoxAttachment(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AtlasRegion FindRegion(string name) {
|
||||||
|
AtlasRegion region;
|
||||||
|
|
||||||
|
for (int i = 0; i < atlasArray.Length; i++) {
|
||||||
|
region = atlasArray[i].FindRegion(name);
|
||||||
|
if (region != null)
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,8 +42,8 @@ namespace Spine {
|
|||||||
private AttachmentLoader attachmentLoader;
|
private AttachmentLoader attachmentLoader;
|
||||||
public float Scale { get; set; }
|
public float Scale { get; set; }
|
||||||
|
|
||||||
public SkeletonJson (Atlas atlas)
|
public SkeletonJson (params Atlas[] atlasArray)
|
||||||
: this(new AtlasAttachmentLoader(atlas)) {
|
: this(new AtlasAttachmentLoader(atlasArray)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkeletonJson (AttachmentLoader attachmentLoader) {
|
public SkeletonJson (AttachmentLoader attachmentLoader) {
|
||||||
|
|||||||
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 63212ccaf5776bd489cba58fb67a2233
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
BIN
spine-unity/Assets/Examples/Scenes/Mix and Match.unity
Normal file
BIN
spine-unity/Assets/Examples/Scenes/Mix and Match.unity
Normal file
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c5673b83016f67a4c99772dfb7b3c437
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
@ -71,11 +71,17 @@ public class BasicPlatformerController : MonoBehaviour {
|
|||||||
#if UNITY_4_5
|
#if UNITY_4_5
|
||||||
[Header("Animation")]
|
[Header("Animation")]
|
||||||
#endif
|
#endif
|
||||||
|
[SpineAnimation(dataSource: "skeletonAnimation")]
|
||||||
public string walkName = "Walk";
|
public string walkName = "Walk";
|
||||||
|
[SpineAnimation(dataSource: "skeletonAnimation")]
|
||||||
public string runName = "Run";
|
public string runName = "Run";
|
||||||
|
[SpineAnimation(dataSource: "skeletonAnimation")]
|
||||||
public string idleName = "Idle";
|
public string idleName = "Idle";
|
||||||
|
[SpineAnimation(dataSource: "skeletonAnimation")]
|
||||||
public string jumpName = "Jump";
|
public string jumpName = "Jump";
|
||||||
|
[SpineAnimation(dataSource: "skeletonAnimation")]
|
||||||
public string fallName = "Fall";
|
public string fallName = "Fall";
|
||||||
|
[SpineAnimation(dataSource: "skeletonAnimation")]
|
||||||
public string crouchName = "Crouch";
|
public string crouchName = "Crouch";
|
||||||
|
|
||||||
#if UNITY_4_5
|
#if UNITY_4_5
|
||||||
|
|||||||
17
spine-unity/Assets/Examples/Scripts/Chimera.cs
Normal file
17
spine-unity/Assets/Examples/Scripts/Chimera.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
public class Chimera : MonoBehaviour {
|
||||||
|
|
||||||
|
public SkeletonDataAsset skeletonDataSource;
|
||||||
|
|
||||||
|
[SpineAttachment(currentSkinOnly: false, returnFullPath: true, dataSource: "skeletonDataSource")]
|
||||||
|
public string attachmentPath;
|
||||||
|
|
||||||
|
[SpineSlot]
|
||||||
|
public string targetSlot;
|
||||||
|
|
||||||
|
void Start() {
|
||||||
|
GetComponent<SkeletonRenderer>().skeleton.FindSlot(targetSlot).Attachment = SpineAttachment.GetAttachment(attachmentPath, skeletonDataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
spine-unity/Assets/Examples/Scripts/Chimera.cs.meta
Normal file
8
spine-unity/Assets/Examples/Scripts/Chimera.cs.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5053fe97a7657b5418b0c307b7338b0c
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
51
spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs
Normal file
51
spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
public class FootSoldierExample : MonoBehaviour {
|
||||||
|
[SpineAnimation("Idle")]
|
||||||
|
public string idleAnimation;
|
||||||
|
|
||||||
|
[SpineAnimation]
|
||||||
|
public string attackAnimation;
|
||||||
|
|
||||||
|
[SpineSlot]
|
||||||
|
public string eyesSlot;
|
||||||
|
|
||||||
|
[SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")]
|
||||||
|
public string eyesOpenAttachment;
|
||||||
|
|
||||||
|
[SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")]
|
||||||
|
public string blinkAttachment;
|
||||||
|
|
||||||
|
[Range(0, 0.2f)]
|
||||||
|
public float blinkDuration = 0.05f;
|
||||||
|
|
||||||
|
private SkeletonAnimation skeletonAnimation;
|
||||||
|
|
||||||
|
void Awake() {
|
||||||
|
skeletonAnimation = GetComponent<SkeletonAnimation>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start() {
|
||||||
|
skeletonAnimation.state.SetAnimation(0, idleAnimation, true);
|
||||||
|
StartCoroutine("Blink");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update() {
|
||||||
|
if (Input.GetKey(KeyCode.Space)) {
|
||||||
|
if (skeletonAnimation.state.GetCurrent(0).Animation.Name != attackAnimation) {
|
||||||
|
skeletonAnimation.state.SetAnimation(0, attackAnimation, false);
|
||||||
|
skeletonAnimation.state.AddAnimation(0, idleAnimation, true, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator Blink() {
|
||||||
|
while (true) {
|
||||||
|
yield return new WaitForSeconds(Random.Range(0.25f, 3f));
|
||||||
|
skeletonAnimation.skeleton.SetAttachment(eyesSlot, blinkAttachment);
|
||||||
|
yield return new WaitForSeconds(blinkDuration);
|
||||||
|
skeletonAnimation.skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3c826b50b0cfee343be3bdbbf59d0f7c
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
Binary file not shown.
Binary file not shown.
5
spine-unity/Assets/Examples/Spine/FootSoldier.meta
Normal file
5
spine-unity/Assets/Examples/Spine/FootSoldier.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7a709e690449c1b40b198bb86f707c41
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e90f1603e5c99c745a28d42e61afe5b2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
Equipment.png
|
||||||
|
size: 512,128
|
||||||
|
format: RGBA8888
|
||||||
|
filter: Linear,Linear
|
||||||
|
repeat: none
|
||||||
|
Equipment/shield1
|
||||||
|
rotate: true
|
||||||
|
xy: 220, 33
|
||||||
|
size: 71, 118
|
||||||
|
orig: 256, 256
|
||||||
|
offset: 92, 69
|
||||||
|
index: -1
|
||||||
|
Equipment/shield2
|
||||||
|
rotate: true
|
||||||
|
xy: 340, 22
|
||||||
|
size: 82, 111
|
||||||
|
orig: 256, 256
|
||||||
|
offset: 87, 72
|
||||||
|
index: -1
|
||||||
|
Equipment/sword1
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 2
|
||||||
|
size: 161, 31
|
||||||
|
orig: 512, 256
|
||||||
|
offset: 217, 112
|
||||||
|
index: -1
|
||||||
|
Equipment/sword4
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 35
|
||||||
|
size: 216, 69
|
||||||
|
orig: 512, 256
|
||||||
|
offset: 200, 94
|
||||||
|
index: -1
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4f0639ff8bc42314d8d62ee0f7ba541f
|
||||||
|
TextScriptImporter:
|
||||||
|
userData:
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
@ -0,0 +1,47 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ddb89f63d0296cf4f8572b0448bb6b30
|
||||||
|
TextureImporter:
|
||||||
|
fileIDToRecycleName: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
linearTexture: 0
|
||||||
|
correctGamma: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: .25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: -3
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
filterMode: -1
|
||||||
|
aniso: -1
|
||||||
|
mipBias: -1
|
||||||
|
wrapMode: -1
|
||||||
|
nPOTScale: 1
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: .5, y: .5}
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
alphaIsTransparency: 0
|
||||||
|
textureType: -1
|
||||||
|
buildTargetSettings: []
|
||||||
|
spriteSheet:
|
||||||
|
sprites: []
|
||||||
|
spritePackingTag:
|
||||||
|
userData:
|
||||||
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c574489dd067c2b4cb4dc165a4c410cc
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e6e388faa521c96449984cfa4b60d74e
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
|
||||||
|
FS_White.png
|
||||||
|
size: 256,256
|
||||||
|
format: RGBA8888
|
||||||
|
filter: Linear,Linear
|
||||||
|
repeat: none
|
||||||
|
White/arm
|
||||||
|
rotate: false
|
||||||
|
xy: 143, 156
|
||||||
|
size: 111, 98
|
||||||
|
orig: 111, 98
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/arm 2
|
||||||
|
rotate: false
|
||||||
|
xy: 95, 36
|
||||||
|
size: 46, 79
|
||||||
|
orig: 46, 79
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/body
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 12
|
||||||
|
size: 91, 103
|
||||||
|
orig: 91, 103
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/eyes
|
||||||
|
rotate: true
|
||||||
|
xy: 195, 87
|
||||||
|
size: 67, 31
|
||||||
|
orig: 67, 31
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/eyes blink
|
||||||
|
rotate: true
|
||||||
|
xy: 228, 87
|
||||||
|
size: 67, 22
|
||||||
|
orig: 67, 22
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/feet
|
||||||
|
rotate: false
|
||||||
|
xy: 95, 2
|
||||||
|
size: 50, 32
|
||||||
|
orig: 50, 32
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/feet 2
|
||||||
|
rotate: false
|
||||||
|
xy: 193, 58
|
||||||
|
size: 55, 27
|
||||||
|
orig: 55, 27
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/hand
|
||||||
|
rotate: false
|
||||||
|
xy: 147, 9
|
||||||
|
size: 32, 28
|
||||||
|
orig: 32, 28
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/head 1
|
||||||
|
rotate: false
|
||||||
|
xy: 2, 117
|
||||||
|
size: 139, 137
|
||||||
|
orig: 139, 137
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/leg
|
||||||
|
rotate: false
|
||||||
|
xy: 143, 39
|
||||||
|
size: 48, 55
|
||||||
|
orig: 48, 55
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/leg 2
|
||||||
|
rotate: false
|
||||||
|
xy: 143, 96
|
||||||
|
size: 50, 58
|
||||||
|
orig: 50, 58
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
White/mouth
|
||||||
|
rotate: false
|
||||||
|
xy: 193, 35
|
||||||
|
size: 28, 21
|
||||||
|
orig: 28, 21
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5ca7c05342912804eb0a2fd5bbe85b58
|
||||||
|
TextScriptImporter:
|
||||||
|
userData:
|
||||||
BIN
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png
Normal file
BIN
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
@ -0,0 +1,47 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 57b57f94df266f94ea0981915a4472e1
|
||||||
|
TextureImporter:
|
||||||
|
fileIDToRecycleName: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
linearTexture: 0
|
||||||
|
correctGamma: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: .25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: -3
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
filterMode: -1
|
||||||
|
aniso: -1
|
||||||
|
mipBias: -1
|
||||||
|
wrapMode: -1
|
||||||
|
nPOTScale: 1
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: .5, y: .5}
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
alphaIsTransparency: 0
|
||||||
|
textureType: -1
|
||||||
|
buildTargetSettings: []
|
||||||
|
spriteSheet:
|
||||||
|
sprites: []
|
||||||
|
spritePackingTag:
|
||||||
|
userData:
|
||||||
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e3c7e74834cd8424f8735ba05e94a688
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5a3598dafa118754db95756064347da7
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
1754
spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json
Normal file
1754
spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b075ad1d14f5db64b941d266e53de57d
|
||||||
|
TextScriptImporter:
|
||||||
|
userData:
|
||||||
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e57cdb51287d3924ebb2ececf816733b
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
Copyright (c) 2014, XDTech
|
||||||
|
|
||||||
|
The project file and images in this "FootSoldier" project are provided for
|
||||||
|
demonstration purposes only and may not be redistributed for any reason nor
|
||||||
|
used as the basis for derivative work.
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6fe8b327d2ab4bd438a63ffec150a911
|
||||||
|
TextScriptImporter:
|
||||||
|
userData:
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5
spine-unity/Assets/Examples/Spine/Hero/license.txt
Normal file
5
spine-unity/Assets/Examples/Spine/Hero/license.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Copyright (c) 2014, XDTech
|
||||||
|
|
||||||
|
The project file and images in this "Hero" project are provided for
|
||||||
|
demonstration purposes only and may not be redistributed for any reason nor
|
||||||
|
used as the basis for derivative work.
|
||||||
4
spine-unity/Assets/Examples/Spine/Hero/license.txt.meta
Normal file
4
spine-unity/Assets/Examples/Spine/Hero/license.txt.meta
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0d9db1748e0cf9f408129df308299463
|
||||||
|
TextScriptImporter:
|
||||||
|
userData:
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
49
spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs
Normal file
49
spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using System.Collections;
|
||||||
|
using Spine;
|
||||||
|
|
||||||
|
|
||||||
|
public class AtlasRegionAttacher : MonoBehaviour {
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public class SlotRegionPair {
|
||||||
|
[SpineSlot]
|
||||||
|
public string slot;
|
||||||
|
|
||||||
|
[SpineAtlasRegion]
|
||||||
|
public string region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtlasAsset atlasAsset;
|
||||||
|
public SlotRegionPair[] attachments;
|
||||||
|
|
||||||
|
[HideInInspector]
|
||||||
|
public SkeletonRenderer skeletonRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
Atlas atlas;
|
||||||
|
|
||||||
|
void Start() {
|
||||||
|
atlas = atlasAsset.GetAtlas();
|
||||||
|
this.skeletonRenderer = GetComponent<SkeletonRenderer>();
|
||||||
|
|
||||||
|
AtlasAttachmentLoader loader = new AtlasAttachmentLoader(atlas);
|
||||||
|
|
||||||
|
float scaleMultiplier = skeletonRenderer.skeletonDataAsset.scale;
|
||||||
|
|
||||||
|
var enumerator = attachments.GetEnumerator();
|
||||||
|
while (enumerator.MoveNext()) {
|
||||||
|
var entry = (SlotRegionPair)enumerator.Current;
|
||||||
|
var regionAttachment = loader.NewRegionAttachment(null, entry.region, entry.region);
|
||||||
|
regionAttachment.Width = regionAttachment.RegionOriginalWidth * scaleMultiplier;
|
||||||
|
regionAttachment.Height = regionAttachment.RegionOriginalHeight * scaleMultiplier;
|
||||||
|
|
||||||
|
regionAttachment.SetColor(new Color(1, 1, 1, 1));
|
||||||
|
regionAttachment.UpdateOffset();
|
||||||
|
|
||||||
|
var slot = this.skeletonRenderer.skeleton.FindSlot(entry.slot);
|
||||||
|
slot.Attachment = regionAttachment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: afde57cc4fd39bb4dbd61b73403ae6a8
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
@ -28,8 +28,14 @@
|
|||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Spine;
|
||||||
|
|
||||||
|
|
||||||
[CustomEditor(typeof(AtlasAsset))]
|
[CustomEditor(typeof(AtlasAsset))]
|
||||||
public class AtlasAssetInspector : Editor {
|
public class AtlasAssetInspector : Editor {
|
||||||
@ -46,9 +52,23 @@ public class AtlasAssetInspector : Editor {
|
|||||||
|
|
||||||
EditorGUILayout.PropertyField(atlasFile);
|
EditorGUILayout.PropertyField(atlasFile);
|
||||||
EditorGUILayout.PropertyField(materials, true);
|
EditorGUILayout.PropertyField(materials, true);
|
||||||
|
|
||||||
|
|
||||||
|
if (atlasFile.objectReferenceValue != null) {
|
||||||
|
Atlas atlas = asset.GetAtlas();
|
||||||
|
FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic);
|
||||||
|
List<AtlasRegion> regions = (List<AtlasRegion>)field.GetValue(atlas);
|
||||||
|
EditorGUILayout.LabelField("Regions");
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
for (int i = 0; i < regions.Count; i++) {
|
||||||
|
EditorGUILayout.LabelField(regions[i].name);
|
||||||
|
}
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (serializedObject.ApplyModifiedProperties() ||
|
if (serializedObject.ApplyModifiedProperties() ||
|
||||||
(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
|
(UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
|
||||||
) {
|
) {
|
||||||
asset.Reset();
|
asset.Reset();
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png
Normal file
BIN
spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 649 B |
@ -0,0 +1,47 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4a1646cf39026224c85ecba92d7d6948
|
||||||
|
TextureImporter:
|
||||||
|
fileIDToRecycleName: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
linearTexture: 1
|
||||||
|
correctGamma: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: .25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: -1
|
||||||
|
maxTextureSize: 1024
|
||||||
|
textureSettings:
|
||||||
|
filterMode: -1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: -1
|
||||||
|
wrapMode: 1
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: .5, y: .5}
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
textureType: 2
|
||||||
|
buildTargetSettings: []
|
||||||
|
spriteSheet:
|
||||||
|
sprites: []
|
||||||
|
spritePackingTag:
|
||||||
|
userData:
|
||||||
@ -5,8 +5,8 @@ TextureImporter:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
mipmaps:
|
mipmaps:
|
||||||
mipMapMode: 0
|
mipMapMode: 0
|
||||||
enableMipMap: 1
|
enableMipMap: 0
|
||||||
linearTexture: 0
|
linearTexture: 1
|
||||||
correctGamma: 0
|
correctGamma: 0
|
||||||
fadeOut: 0
|
fadeOut: 0
|
||||||
borderMipMap: 0
|
borderMipMap: 0
|
||||||
@ -25,10 +25,10 @@ TextureImporter:
|
|||||||
maxTextureSize: 1024
|
maxTextureSize: 1024
|
||||||
textureSettings:
|
textureSettings:
|
||||||
filterMode: -1
|
filterMode: -1
|
||||||
aniso: -1
|
aniso: 1
|
||||||
mipBias: -1
|
mipBias: -1
|
||||||
wrapMode: -1
|
wrapMode: 1
|
||||||
nPOTScale: 1
|
nPOTScale: 0
|
||||||
lightmap: 0
|
lightmap: 0
|
||||||
compressionQuality: 50
|
compressionQuality: 50
|
||||||
spriteMode: 0
|
spriteMode: 0
|
||||||
@ -38,8 +38,8 @@ TextureImporter:
|
|||||||
spritePivot: {x: .5, y: .5}
|
spritePivot: {x: .5, y: .5}
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
spritePixelsToUnits: 100
|
spritePixelsToUnits: 100
|
||||||
alphaIsTransparency: 0
|
alphaIsTransparency: 1
|
||||||
textureType: -1
|
textureType: 2
|
||||||
buildTargetSettings: []
|
buildTargetSettings: []
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
sprites: []
|
sprites: []
|
||||||
|
|||||||
BIN
spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png
Normal file
BIN
spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 698 B |
@ -0,0 +1,47 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0b1bcb09fa228d049ba3c9ea6a57e1ee
|
||||||
|
TextureImporter:
|
||||||
|
fileIDToRecycleName: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
linearTexture: 1
|
||||||
|
correctGamma: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: .25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: -1
|
||||||
|
maxTextureSize: 1024
|
||||||
|
textureSettings:
|
||||||
|
filterMode: -1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: -1
|
||||||
|
wrapMode: 1
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: .5, y: .5}
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
textureType: 2
|
||||||
|
buildTargetSettings: []
|
||||||
|
spriteSheet:
|
||||||
|
sprites: []
|
||||||
|
spritePackingTag:
|
||||||
|
userData:
|
||||||
@ -44,42 +44,46 @@ using Spine;
|
|||||||
|
|
||||||
[CustomEditor(typeof(SkeletonDataAsset))]
|
[CustomEditor(typeof(SkeletonDataAsset))]
|
||||||
public class SkeletonDataAssetInspector : Editor {
|
public class SkeletonDataAssetInspector : Editor {
|
||||||
private SerializedProperty atlasAsset, skeletonJSON, scale, fromAnimation, toAnimation, duration, defaultMix;
|
static bool showAnimationStateData = true;
|
||||||
private bool showAnimationStateData = true;
|
static bool showAnimationList = true;
|
||||||
|
static bool showSlotList = false;
|
||||||
#if UNITY_4_3
|
static bool showAttachments = false;
|
||||||
private bool m_showAnimationList = true;
|
|
||||||
#else
|
private SerializedProperty atlasAssets, skeletonJSON, scale, fromAnimation, toAnimation, duration, defaultMix;
|
||||||
private AnimBool m_showAnimationList = new AnimBool(true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private bool m_initialized = false;
|
private bool m_initialized = false;
|
||||||
private SkeletonDataAsset m_skeletonDataAsset;
|
private SkeletonDataAsset m_skeletonDataAsset;
|
||||||
|
private SkeletonData m_skeletonData;
|
||||||
private string m_skeletonDataAssetGUID;
|
private string m_skeletonDataAssetGUID;
|
||||||
|
|
||||||
void OnEnable () {
|
|
||||||
try {
|
|
||||||
|
|
||||||
atlasAsset = serializedObject.FindProperty("atlasAsset");
|
List<string> warnings = new List<string>();
|
||||||
|
|
||||||
|
void OnEnable() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
atlasAssets = serializedObject.FindProperty("atlasAssets");
|
||||||
skeletonJSON = serializedObject.FindProperty("skeletonJSON");
|
skeletonJSON = serializedObject.FindProperty("skeletonJSON");
|
||||||
scale = serializedObject.FindProperty("scale");
|
scale = serializedObject.FindProperty("scale");
|
||||||
fromAnimation = serializedObject.FindProperty("fromAnimation");
|
fromAnimation = serializedObject.FindProperty("fromAnimation");
|
||||||
toAnimation = serializedObject.FindProperty("toAnimation");
|
toAnimation = serializedObject.FindProperty("toAnimation");
|
||||||
duration = serializedObject.FindProperty("duration");
|
duration = serializedObject.FindProperty("duration");
|
||||||
defaultMix = serializedObject.FindProperty("defaultMix");
|
defaultMix = serializedObject.FindProperty("defaultMix");
|
||||||
|
|
||||||
m_skeletonDataAsset = (SkeletonDataAsset)target;
|
m_skeletonDataAsset = (SkeletonDataAsset)target;
|
||||||
m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_skeletonDataAsset));
|
m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_skeletonDataAsset));
|
||||||
|
|
||||||
EditorApplication.update += Update;
|
|
||||||
|
|
||||||
|
EditorApplication.update += Update;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_skeletonData = m_skeletonDataAsset.GetSkeletonData(true);
|
||||||
|
|
||||||
|
RepopulateWarnings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDestroy () {
|
void OnDestroy() {
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
EditorApplication.update -= Update;
|
EditorApplication.update -= Update;
|
||||||
this.DestroyPreviewInstances();
|
this.DestroyPreviewInstances();
|
||||||
@ -88,13 +92,13 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
this.m_previewUtility = null;
|
this.m_previewUtility = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void OnInspectorGUI () {
|
override public void OnInspectorGUI() {
|
||||||
serializedObject.Update();
|
serializedObject.Update();
|
||||||
SkeletonDataAsset asset = (SkeletonDataAsset)target;
|
SkeletonDataAsset asset = (SkeletonDataAsset)target;
|
||||||
|
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
EditorGUILayout.PropertyField(atlasAsset);
|
EditorGUILayout.PropertyField(atlasAssets, true);
|
||||||
EditorGUILayout.PropertyField(skeletonJSON);
|
EditorGUILayout.PropertyField(skeletonJSON);
|
||||||
EditorGUILayout.PropertyField(scale);
|
EditorGUILayout.PropertyField(scale);
|
||||||
if (EditorGUI.EndChangeCheck()) {
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
@ -102,142 +106,301 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
m_previewUtility.Cleanup();
|
m_previewUtility.Cleanup();
|
||||||
m_previewUtility = null;
|
m_previewUtility = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RepopulateWarnings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SkeletonData skeletonData = asset.GetSkeletonData(asset.atlasAsset == null || asset.skeletonJSON == null);
|
if (m_skeletonData != null) {
|
||||||
if (skeletonData != null) {
|
|
||||||
showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data");
|
DrawAnimationStateInfo();
|
||||||
if (showAnimationStateData) {
|
DrawAnimationList();
|
||||||
EditorGUILayout.PropertyField(defaultMix);
|
DrawSlotList();
|
||||||
|
|
||||||
// Animation names
|
|
||||||
String[] animations = new String[skeletonData.Animations.Count];
|
|
||||||
for (int i = 0; i < animations.Length; i++)
|
|
||||||
animations[i] = skeletonData.Animations[i].Name;
|
|
||||||
|
|
||||||
for (int i = 0; i < fromAnimation.arraySize; i++) {
|
|
||||||
SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
|
|
||||||
SerializedProperty to = toAnimation.GetArrayElementAtIndex(i);
|
|
||||||
SerializedProperty durationProp = duration.GetArrayElementAtIndex(i);
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)];
|
|
||||||
to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)];
|
|
||||||
durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue);
|
|
||||||
if (GUILayout.Button("Delete")) {
|
|
||||||
duration.DeleteArrayElementAtIndex(i);
|
|
||||||
toAnimation.DeleteArrayElementAtIndex(i);
|
|
||||||
fromAnimation.DeleteArrayElementAtIndex(i);
|
|
||||||
}
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
EditorGUILayout.Space();
|
|
||||||
if (GUILayout.Button("Add Mix")) {
|
|
||||||
duration.arraySize++;
|
|
||||||
toAnimation.arraySize++;
|
|
||||||
fromAnimation.arraySize++;
|
|
||||||
}
|
|
||||||
EditorGUILayout.Space();
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
|
} else {
|
||||||
StopAnimation();
|
//Show Warnings
|
||||||
m_skeletonAnimation.skeleton.SetToSetupPose();
|
foreach (var str in warnings)
|
||||||
m_requireRefresh = true;
|
EditorGUILayout.LabelField(new GUIContent(str, SpineEditorUtilities.Icons.warning));
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_4_3
|
|
||||||
m_showAnimationList = EditorGUILayout.Foldout(m_showAnimationList, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot));
|
|
||||||
if(m_showAnimationList){
|
|
||||||
#else
|
|
||||||
m_showAnimationList.target = EditorGUILayout.Foldout(m_showAnimationList.target, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot));
|
|
||||||
if (EditorGUILayout.BeginFadeGroup(m_showAnimationList.faded)) {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EditorGUILayout.LabelField("Name", "Duration");
|
|
||||||
foreach (Spine.Animation a in skeletonData.Animations) {
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
|
|
||||||
if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
|
|
||||||
if (m_skeletonAnimation.state.GetCurrent(0) != null && m_skeletonAnimation.state.GetCurrent(0).Animation == a) {
|
|
||||||
GUI.contentColor = Color.black;
|
|
||||||
if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
|
|
||||||
StopAnimation();
|
|
||||||
}
|
|
||||||
GUI.contentColor = Color.white;
|
|
||||||
} else {
|
|
||||||
if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
|
|
||||||
PlayAnimation(a.Name, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GUILayout.Label("?", GUILayout.Width(24));
|
|
||||||
}
|
|
||||||
EditorGUILayout.LabelField(new GUIContent(a.Name, SpineEditorUtilities.Icons.animation), new GUIContent(a.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(a.Duration * 30)) + ")").PadLeft(12, ' ')));
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if !UNITY_4_3
|
|
||||||
EditorGUILayout.EndFadeGroup();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Application.isPlaying) {
|
if (!Application.isPlaying) {
|
||||||
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")
|
||||||
) {
|
) {
|
||||||
asset.Reset();
|
asset.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawAnimationStateInfo() {
|
||||||
|
showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data");
|
||||||
|
if (!showAnimationStateData)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(defaultMix);
|
||||||
|
|
||||||
|
// Animation names
|
||||||
|
String[] animations = new String[m_skeletonData.Animations.Count];
|
||||||
|
for (int i = 0; i < animations.Length; i++)
|
||||||
|
animations[i] = m_skeletonData.Animations[i].Name;
|
||||||
|
|
||||||
|
for (int i = 0; i < fromAnimation.arraySize; i++) {
|
||||||
|
SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
|
||||||
|
SerializedProperty to = toAnimation.GetArrayElementAtIndex(i);
|
||||||
|
SerializedProperty durationProp = duration.GetArrayElementAtIndex(i);
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)];
|
||||||
|
to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)];
|
||||||
|
durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue);
|
||||||
|
if (GUILayout.Button("Delete")) {
|
||||||
|
duration.DeleteArrayElementAtIndex(i);
|
||||||
|
toAnimation.DeleteArrayElementAtIndex(i);
|
||||||
|
fromAnimation.DeleteArrayElementAtIndex(i);
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
if (GUILayout.Button("Add Mix")) {
|
||||||
|
duration.arraySize++;
|
||||||
|
toAnimation.arraySize++;
|
||||||
|
fromAnimation.arraySize++;
|
||||||
|
}
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
}
|
||||||
|
void DrawAnimationList() {
|
||||||
|
showAnimationList = EditorGUILayout.Foldout(showAnimationList, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot));
|
||||||
|
if (!showAnimationList)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
|
||||||
|
StopAnimation();
|
||||||
|
m_skeletonAnimation.skeleton.SetToSetupPose();
|
||||||
|
m_requireRefresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField("Name", "Duration");
|
||||||
|
foreach (Spine.Animation a in m_skeletonData.Animations) {
|
||||||
|
GUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
|
||||||
|
if (m_skeletonAnimation.state.GetCurrent(0) != null && m_skeletonAnimation.state.GetCurrent(0).Animation == a) {
|
||||||
|
GUI.contentColor = Color.black;
|
||||||
|
if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
|
||||||
|
StopAnimation();
|
||||||
|
}
|
||||||
|
GUI.contentColor = Color.white;
|
||||||
|
} else {
|
||||||
|
if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
|
||||||
|
PlayAnimation(a.Name, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GUILayout.Label("?", GUILayout.Width(24));
|
||||||
|
}
|
||||||
|
EditorGUILayout.LabelField(new GUIContent(a.Name, SpineEditorUtilities.Icons.animation), new GUIContent(a.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(a.Duration * 30)) + ")").PadLeft(12, ' ')));
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DrawSlotList() {
|
||||||
|
showSlotList = EditorGUILayout.Foldout(showSlotList, new GUIContent("Slots", SpineEditorUtilities.Icons.slotRoot));
|
||||||
|
|
||||||
|
if (!showSlotList)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_skeletonAnimation == null || m_skeletonAnimation.skeleton == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
try {
|
||||||
|
showAttachments = EditorGUILayout.ToggleLeft("Show Attachments", showAttachments);
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<Attachment> slotAttachments = new List<Attachment>();
|
||||||
|
List<string> slotAttachmentNames = new List<string>();
|
||||||
|
List<string> defaultSkinAttachmentNames = new List<string>();
|
||||||
|
var defaultSkin = m_skeletonData.Skins[0];
|
||||||
|
Skin skin = m_skeletonAnimation.skeleton.Skin;
|
||||||
|
if (skin == null) {
|
||||||
|
skin = defaultSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = m_skeletonAnimation.skeleton.Slots.Count-1; i >= 0; i--) {
|
||||||
|
Slot slot = m_skeletonAnimation.skeleton.Slots[i];
|
||||||
|
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, SpineEditorUtilities.Icons.slot));
|
||||||
|
if (showAttachments) {
|
||||||
|
|
||||||
|
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
slotAttachments.Clear();
|
||||||
|
slotAttachmentNames.Clear();
|
||||||
|
defaultSkinAttachmentNames.Clear();
|
||||||
|
|
||||||
|
skin.FindNamesForSlot(i, slotAttachmentNames);
|
||||||
|
skin.FindAttachmentsForSlot(i, slotAttachments);
|
||||||
|
|
||||||
|
|
||||||
|
if (skin != defaultSkin) {
|
||||||
|
defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
|
||||||
|
defaultSkin.FindNamesForSlot(i, slotAttachmentNames);
|
||||||
|
defaultSkin.FindAttachmentsForSlot(i, slotAttachments);
|
||||||
|
} else {
|
||||||
|
defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (int a = 0; a < slotAttachments.Count; a++) {
|
||||||
|
Attachment attachment = slotAttachments[a];
|
||||||
|
string name = slotAttachmentNames[a];
|
||||||
|
|
||||||
|
Texture2D icon = null;
|
||||||
|
var type = attachment.GetType();
|
||||||
|
|
||||||
|
if (type == typeof(RegionAttachment))
|
||||||
|
icon = SpineEditorUtilities.Icons.image;
|
||||||
|
else if (type == typeof(MeshAttachment))
|
||||||
|
icon = SpineEditorUtilities.Icons.mesh;
|
||||||
|
else if (type == typeof(BoundingBoxAttachment))
|
||||||
|
icon = SpineEditorUtilities.Icons.boundingBox;
|
||||||
|
else if (type == typeof(SkinnedMeshAttachment))
|
||||||
|
icon = SpineEditorUtilities.Icons.weights;
|
||||||
|
else
|
||||||
|
icon = SpineEditorUtilities.Icons.warning;
|
||||||
|
|
||||||
|
//TODO: Waterboard Nate
|
||||||
|
//if (name != attachment.Name)
|
||||||
|
//icon = SpineEditorUtilities.Icons.skinPlaceholder;
|
||||||
|
|
||||||
|
bool initialState = slot.Attachment == attachment;
|
||||||
|
|
||||||
|
bool toggled = EditorGUILayout.ToggleLeft(new GUIContent(name, icon), slot.Attachment == attachment);
|
||||||
|
|
||||||
|
if (!defaultSkinAttachmentNames.Contains(name)) {
|
||||||
|
Rect skinPlaceHolderIconRect = GUILayoutUtility.GetLastRect();
|
||||||
|
skinPlaceHolderIconRect.width = SpineEditorUtilities.Icons.skinPlaceholder.width;
|
||||||
|
skinPlaceHolderIconRect.height = SpineEditorUtilities.Icons.skinPlaceholder.height;
|
||||||
|
GUI.DrawTexture(skinPlaceHolderIconRect, SpineEditorUtilities.Icons.skinPlaceholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (toggled != initialState) {
|
||||||
|
if (toggled) {
|
||||||
|
slot.Attachment = attachment;
|
||||||
|
} else {
|
||||||
|
slot.Attachment = null;
|
||||||
|
}
|
||||||
|
m_requireRefresh = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RepopulateWarnings() {
|
||||||
|
warnings.Clear();
|
||||||
|
|
||||||
|
if (skeletonJSON.objectReferenceValue == null)
|
||||||
|
warnings.Add("Missing Skeleton JSON");
|
||||||
|
else {
|
||||||
|
|
||||||
|
if (SpineEditorUtilities.IsSpineJSON((TextAsset)skeletonJSON.objectReferenceValue) == false) {
|
||||||
|
warnings.Add("Skeleton JSON is not a Valid JSON file");
|
||||||
|
} else {
|
||||||
|
bool detectedNullAtlasEntry = false;
|
||||||
|
List<Atlas> atlasList = new List<Atlas>();
|
||||||
|
for (int i = 0; i < atlasAssets.arraySize; i++) {
|
||||||
|
if (atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue == null) {
|
||||||
|
detectedNullAtlasEntry = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
atlasList.Add(((AtlasAsset)atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue).GetAtlas());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detectedNullAtlasEntry)
|
||||||
|
warnings.Add("AtlasAsset elements cannot be Null");
|
||||||
|
else {
|
||||||
|
//get requirements
|
||||||
|
var missingPaths = SpineEditorUtilities.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath((TextAsset)skeletonJSON.objectReferenceValue));
|
||||||
|
|
||||||
|
foreach (var atlas in atlasList) {
|
||||||
|
for (int i = 0; i < missingPaths.Count; i++) {
|
||||||
|
if (atlas.FindRegion(missingPaths[i]) != null) {
|
||||||
|
missingPaths.RemoveAt(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var str in missingPaths)
|
||||||
|
warnings.Add("Missing Region: '" + str + "'");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//preview window stuff
|
//preview window stuff
|
||||||
private PreviewRenderUtility m_previewUtility;
|
private PreviewRenderUtility m_previewUtility;
|
||||||
private GameObject m_previewInstance;
|
private GameObject m_previewInstance;
|
||||||
private Vector2 previewDir;
|
private Vector2 previewDir;
|
||||||
private SkeletonAnimation m_skeletonAnimation;
|
private SkeletonAnimation m_skeletonAnimation;
|
||||||
private SkeletonData m_skeletonData;
|
//private SkeletonData m_skeletonData;
|
||||||
private static int sliderHash = "Slider".GetHashCode();
|
private static int sliderHash = "Slider".GetHashCode();
|
||||||
private float m_lastTime;
|
private float m_lastTime;
|
||||||
private bool m_playing;
|
private bool m_playing;
|
||||||
private bool m_requireRefresh;
|
private bool m_requireRefresh;
|
||||||
private Color m_originColor = new Color(0.3f, 0.3f, 0.3f, 1);
|
private Color m_originColor = new Color(0.3f, 0.3f, 0.3f, 1);
|
||||||
|
|
||||||
private void StopAnimation () {
|
private void StopAnimation() {
|
||||||
m_skeletonAnimation.state.ClearTrack(0);
|
m_skeletonAnimation.state.ClearTrack(0);
|
||||||
m_playing = false;
|
m_playing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Spine.Event> m_animEvents = new List<Spine.Event>();
|
List<Spine.Event> m_animEvents = new List<Spine.Event>();
|
||||||
List<float> m_animEventFrames = new List<float>();
|
List<float> m_animEventFrames = new List<float>();
|
||||||
|
|
||||||
private void PlayAnimation (string animName, bool loop) {
|
private void PlayAnimation(string animName, bool loop) {
|
||||||
m_animEvents.Clear();
|
m_animEvents.Clear();
|
||||||
m_animEventFrames.Clear();
|
m_animEventFrames.Clear();
|
||||||
|
|
||||||
m_skeletonAnimation.state.SetAnimation(0, animName, loop);
|
m_skeletonAnimation.state.SetAnimation(0, animName, loop);
|
||||||
|
|
||||||
Spine.Animation a = m_skeletonAnimation.state.GetCurrent(0).Animation;
|
Spine.Animation a = m_skeletonAnimation.state.GetCurrent(0).Animation;
|
||||||
foreach (Timeline t in a.Timelines) {
|
foreach (Timeline t in a.Timelines) {
|
||||||
if (t.GetType() == typeof(EventTimeline)) {
|
if (t.GetType() == typeof(EventTimeline)) {
|
||||||
EventTimeline et = (EventTimeline)t;
|
EventTimeline et = (EventTimeline)t;
|
||||||
|
|
||||||
for (int i = 0; i < et.Events.Length; i++) {
|
for (int i = 0; i < et.Events.Length; i++) {
|
||||||
m_animEvents.Add(et.Events[i]);
|
m_animEvents.Add(et.Events[i]);
|
||||||
m_animEventFrames.Add(et.Frames[i]);
|
m_animEventFrames.Add(et.Frames[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_playing = true;
|
m_playing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitPreview () {
|
private void InitPreview() {
|
||||||
if (this.m_previewUtility == null) {
|
if (this.m_previewUtility == null) {
|
||||||
this.m_lastTime = Time.realtimeSinceStartup;
|
this.m_lastTime = Time.realtimeSinceStartup;
|
||||||
this.m_previewUtility = new PreviewRenderUtility(true);
|
this.m_previewUtility = new PreviewRenderUtility(true);
|
||||||
@ -247,48 +410,59 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
this.CreatePreviewInstances();
|
this.CreatePreviewInstances();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreatePreviewInstances () {
|
private void CreatePreviewInstances() {
|
||||||
this.DestroyPreviewInstances();
|
this.DestroyPreviewInstances();
|
||||||
if (this.m_previewInstance == null) {
|
if (this.m_previewInstance == null) {
|
||||||
string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", "");
|
try {
|
||||||
|
string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", "");
|
||||||
m_previewInstance = SpineEditorUtilities.SpawnAnimatedSkeleton((SkeletonDataAsset)target, skinName).gameObject;
|
|
||||||
m_previewInstance.hideFlags = HideFlags.HideAndDontSave;
|
m_previewInstance = SpineEditorUtilities.SpawnAnimatedSkeleton((SkeletonDataAsset)target, skinName).gameObject;
|
||||||
m_previewInstance.layer = 0x1f;
|
m_previewInstance.hideFlags = HideFlags.HideAndDontSave;
|
||||||
|
m_previewInstance.layer = 0x1f;
|
||||||
|
|
||||||
m_skeletonAnimation = m_previewInstance.GetComponent<SkeletonAnimation>();
|
|
||||||
m_skeletonAnimation.initialSkinName = skinName;
|
m_skeletonAnimation = m_previewInstance.GetComponent<SkeletonAnimation>();
|
||||||
m_skeletonAnimation.LateUpdate();
|
m_skeletonAnimation.initialSkinName = skinName;
|
||||||
|
m_skeletonAnimation.LateUpdate();
|
||||||
m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true);
|
|
||||||
|
m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true);
|
||||||
m_previewInstance.renderer.enabled = false;
|
|
||||||
|
m_previewInstance.renderer.enabled = false;
|
||||||
m_initialized = true;
|
|
||||||
AdjustCameraGoals(true);
|
m_initialized = true;
|
||||||
|
AdjustCameraGoals(true);
|
||||||
|
} catch {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DestroyPreviewInstances () {
|
private void DestroyPreviewInstances() {
|
||||||
if (this.m_previewInstance != null) {
|
if (this.m_previewInstance != null) {
|
||||||
DestroyImmediate(this.m_previewInstance);
|
DestroyImmediate(this.m_previewInstance);
|
||||||
m_previewInstance = null;
|
m_previewInstance = null;
|
||||||
}
|
}
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HasPreviewGUI () {
|
public override bool HasPreviewGUI() {
|
||||||
//TODO: validate json data
|
//TODO: validate json data
|
||||||
|
|
||||||
|
for (int i = 0; i < atlasAssets.arraySize; i++) {
|
||||||
|
var prop = atlasAssets.GetArrayElementAtIndex(i);
|
||||||
|
if (prop.objectReferenceValue == null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return skeletonJSON.objectReferenceValue != null;
|
return skeletonJSON.objectReferenceValue != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture m_previewTex = new Texture();
|
Texture m_previewTex = new Texture();
|
||||||
|
|
||||||
public override void OnInteractivePreviewGUI (Rect r, GUIStyle background) {
|
public override void OnInteractivePreviewGUI(Rect r, GUIStyle background) {
|
||||||
this.InitPreview();
|
this.InitPreview();
|
||||||
|
|
||||||
if (UnityEngine.Event.current.type == EventType.Repaint) {
|
if (UnityEngine.Event.current.type == EventType.Repaint) {
|
||||||
if (m_requireRefresh) {
|
if (m_requireRefresh) {
|
||||||
this.m_previewUtility.BeginPreview(r, background);
|
this.m_previewUtility.BeginPreview(r, background);
|
||||||
@ -299,50 +473,54 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
if (this.m_previewTex != null)
|
if (this.m_previewTex != null)
|
||||||
GUI.DrawTexture(r, m_previewTex, ScaleMode.StretchToFill, false);
|
GUI.DrawTexture(r, m_previewTex, ScaleMode.StretchToFill, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawSkinToolbar(r);
|
DrawSkinToolbar(r);
|
||||||
NormalizedTimeBar(r);
|
NormalizedTimeBar(r);
|
||||||
//TODO: implement panning
|
//TODO: implement panning
|
||||||
// this.previewDir = Drag2D(this.previewDir, r);
|
// this.previewDir = Drag2D(this.previewDir, r);
|
||||||
MouseScroll(r);
|
MouseScroll(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
float m_orthoGoal = 1;
|
float m_orthoGoal = 1;
|
||||||
Vector3 m_posGoal = new Vector3(0, 0, -10);
|
Vector3 m_posGoal = new Vector3(0, 0, -10);
|
||||||
double m_adjustFrameEndTime = 0;
|
double m_adjustFrameEndTime = 0;
|
||||||
|
|
||||||
private void AdjustCameraGoals (bool calculateMixTime) {
|
private void AdjustCameraGoals(bool calculateMixTime) {
|
||||||
|
if (this.m_previewInstance == null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (calculateMixTime) {
|
if (calculateMixTime) {
|
||||||
if (m_skeletonAnimation.state.GetCurrent(0) != null) {
|
if (m_skeletonAnimation.state.GetCurrent(0) != null) {
|
||||||
m_adjustFrameEndTime = EditorApplication.timeSinceStartup + m_skeletonAnimation.state.GetCurrent(0).Mix;
|
m_adjustFrameEndTime = EditorApplication.timeSinceStartup + m_skeletonAnimation.state.GetCurrent(0).Mix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GameObject go = this.m_previewInstance;
|
GameObject go = this.m_previewInstance;
|
||||||
|
|
||||||
Bounds bounds = go.renderer.bounds;
|
Bounds bounds = go.renderer.bounds;
|
||||||
m_orthoGoal = bounds.size.y;
|
m_orthoGoal = bounds.size.y;
|
||||||
|
|
||||||
m_posGoal = bounds.center + new Vector3(0, 0, -10);
|
m_posGoal = bounds.center + new Vector3(0, 0, -10);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AdjustCameraGoals () {
|
private void AdjustCameraGoals() {
|
||||||
AdjustCameraGoals(false);
|
AdjustCameraGoals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AdjustCamera () {
|
private void AdjustCamera() {
|
||||||
if (m_previewUtility == null)
|
if (m_previewUtility == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
if (EditorApplication.timeSinceStartup < m_adjustFrameEndTime) {
|
if (EditorApplication.timeSinceStartup < m_adjustFrameEndTime) {
|
||||||
AdjustCameraGoals();
|
AdjustCameraGoals();
|
||||||
}
|
}
|
||||||
|
|
||||||
float orthoSet = Mathf.Lerp(this.m_previewUtility.m_Camera.orthographicSize, m_orthoGoal, 0.1f);
|
float orthoSet = Mathf.Lerp(this.m_previewUtility.m_Camera.orthographicSize, m_orthoGoal, 0.1f);
|
||||||
|
|
||||||
this.m_previewUtility.m_Camera.orthographicSize = orthoSet;
|
this.m_previewUtility.m_Camera.orthographicSize = orthoSet;
|
||||||
|
|
||||||
float dist = Vector3.Distance(m_previewUtility.m_Camera.transform.position, m_posGoal);
|
float dist = Vector3.Distance(m_previewUtility.m_Camera.transform.position, m_posGoal);
|
||||||
if (dist > 60f * ((SkeletonDataAsset)target).scale) {
|
if (dist > 60f * ((SkeletonDataAsset)target).scale) {
|
||||||
Vector3 pos = Vector3.Lerp(this.m_previewUtility.m_Camera.transform.position, m_posGoal, 0.1f);
|
Vector3 pos = Vector3.Lerp(this.m_previewUtility.m_Camera.transform.position, m_posGoal, 0.1f);
|
||||||
@ -352,138 +530,138 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
m_requireRefresh = true;
|
m_requireRefresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DoRenderPreview (bool drawHandles) {
|
private void DoRenderPreview(bool drawHandles) {
|
||||||
GameObject go = this.m_previewInstance;
|
GameObject go = this.m_previewInstance;
|
||||||
|
|
||||||
if (m_requireRefresh) {
|
if (m_requireRefresh && go != null) {
|
||||||
go.renderer.enabled = true;
|
go.renderer.enabled = true;
|
||||||
|
|
||||||
if (EditorApplication.isPlaying) {
|
if (EditorApplication.isPlaying) {
|
||||||
//do nothing
|
//do nothing
|
||||||
} else {
|
} else {
|
||||||
m_skeletonAnimation.Update((Time.realtimeSinceStartup - m_lastTime));
|
m_skeletonAnimation.Update((Time.realtimeSinceStartup - m_lastTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_lastTime = Time.realtimeSinceStartup;
|
m_lastTime = Time.realtimeSinceStartup;
|
||||||
|
|
||||||
if (!EditorApplication.isPlaying)
|
if (!EditorApplication.isPlaying)
|
||||||
m_skeletonAnimation.LateUpdate();
|
m_skeletonAnimation.LateUpdate();
|
||||||
|
|
||||||
if (drawHandles) {
|
if (drawHandles) {
|
||||||
Handles.SetCamera(m_previewUtility.m_Camera);
|
Handles.SetCamera(m_previewUtility.m_Camera);
|
||||||
Handles.color = m_originColor;
|
Handles.color = m_originColor;
|
||||||
|
|
||||||
Handles.DrawLine(new Vector3(-1000 * m_skeletonDataAsset.scale, 0, 0), new Vector3(1000 * m_skeletonDataAsset.scale, 0, 0));
|
Handles.DrawLine(new Vector3(-1000 * m_skeletonDataAsset.scale, 0, 0), new Vector3(1000 * m_skeletonDataAsset.scale, 0, 0));
|
||||||
Handles.DrawLine(new Vector3(0, 1000 * m_skeletonDataAsset.scale, 0), new Vector3(0, -1000 * m_skeletonDataAsset.scale, 0));
|
Handles.DrawLine(new Vector3(0, 1000 * m_skeletonDataAsset.scale, 0), new Vector3(0, -1000 * m_skeletonDataAsset.scale, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.m_previewUtility.m_Camera.Render();
|
this.m_previewUtility.m_Camera.Render();
|
||||||
go.renderer.enabled = false;
|
go.renderer.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update () {
|
void Update() {
|
||||||
AdjustCamera();
|
AdjustCamera();
|
||||||
|
|
||||||
if (m_playing) {
|
if (m_playing) {
|
||||||
m_requireRefresh = true;
|
m_requireRefresh = true;
|
||||||
Repaint();
|
Repaint();
|
||||||
} else if (m_requireRefresh) {
|
} else if (m_requireRefresh) {
|
||||||
Repaint();
|
Repaint();
|
||||||
} else {
|
} else {
|
||||||
#if !UNITY_4_3
|
//only needed if using smooth menus
|
||||||
if (m_showAnimationList.isAnimating)
|
}
|
||||||
Repaint();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawSkinToolbar (Rect r) {
|
void DrawSkinToolbar(Rect r) {
|
||||||
if (m_skeletonAnimation == null)
|
if (m_skeletonAnimation == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_skeletonAnimation.skeleton != null) {
|
if (m_skeletonAnimation.skeleton != null) {
|
||||||
string label = (m_skeletonAnimation.skeleton != null && m_skeletonAnimation.skeleton.Skin != null) ? m_skeletonAnimation.skeleton.Skin.Name : "default";
|
string label = (m_skeletonAnimation.skeleton != null && m_skeletonAnimation.skeleton.Skin != null) ? m_skeletonAnimation.skeleton.Skin.Name : "default";
|
||||||
|
|
||||||
Rect popRect = new Rect(r);
|
Rect popRect = new Rect(r);
|
||||||
popRect.y += 32;
|
popRect.y += 32;
|
||||||
popRect.x += 4;
|
popRect.x += 4;
|
||||||
popRect.height = 24;
|
popRect.height = 24;
|
||||||
popRect.width = 40;
|
popRect.width = 40;
|
||||||
EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", SpineEditorUtilities.Icons.skinsRoot));
|
EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", SpineEditorUtilities.Icons.skinsRoot));
|
||||||
|
|
||||||
popRect.y += 11;
|
popRect.y += 11;
|
||||||
popRect.width = 150;
|
popRect.width = 150;
|
||||||
popRect.x += 44;
|
popRect.x += 44;
|
||||||
|
|
||||||
if (GUI.Button(popRect, label, EditorStyles.popup)) {
|
if (GUI.Button(popRect, label, EditorStyles.popup)) {
|
||||||
SelectSkinContext();
|
SelectSkinContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectSkinContext () {
|
void SelectSkinContext() {
|
||||||
GenericMenu menu = new GenericMenu();
|
GenericMenu menu = new GenericMenu();
|
||||||
|
|
||||||
foreach (Skin s in m_skeletonData.Skins) {
|
foreach (Skin s in m_skeletonData.Skins) {
|
||||||
menu.AddItem(new GUIContent(s.Name), this.m_skeletonAnimation.skeleton.Skin == s, SetSkin, (object)s);
|
menu.AddItem(new GUIContent(s.Name), this.m_skeletonAnimation.skeleton.Skin == s, SetSkin, (object)s);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.ShowAsContext();
|
menu.ShowAsContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSkin (object o) {
|
void SetSkin(object o) {
|
||||||
Skin skin = (Skin)o;
|
Skin skin = (Skin)o;
|
||||||
|
|
||||||
m_skeletonAnimation.initialSkinName = skin.Name;
|
m_skeletonAnimation.initialSkinName = skin.Name;
|
||||||
m_skeletonAnimation.Reset();
|
m_skeletonAnimation.Reset();
|
||||||
m_requireRefresh = true;
|
m_requireRefresh = true;
|
||||||
|
|
||||||
EditorPrefs.SetString(m_skeletonDataAssetGUID + "_lastSkin", skin.Name);
|
EditorPrefs.SetString(m_skeletonDataAssetGUID + "_lastSkin", skin.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NormalizedTimeBar (Rect r) {
|
void NormalizedTimeBar(Rect r) {
|
||||||
|
if (m_skeletonAnimation == null)
|
||||||
|
return;
|
||||||
|
|
||||||
Rect barRect = new Rect(r);
|
Rect barRect = new Rect(r);
|
||||||
barRect.height = 32;
|
barRect.height = 32;
|
||||||
barRect.x += 4;
|
barRect.x += 4;
|
||||||
barRect.width -= 4;
|
barRect.width -= 4;
|
||||||
|
|
||||||
GUI.Box(barRect, "");
|
GUI.Box(barRect, "");
|
||||||
|
|
||||||
Rect lineRect = new Rect(barRect);
|
Rect lineRect = new Rect(barRect);
|
||||||
float width = lineRect.width;
|
float width = lineRect.width;
|
||||||
TrackEntry t = m_skeletonAnimation.state.GetCurrent(0);
|
TrackEntry t = m_skeletonAnimation.state.GetCurrent(0);
|
||||||
|
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
int loopCount = (int)(t.Time / t.EndTime);
|
int loopCount = (int)(t.Time / t.EndTime);
|
||||||
float currentTime = t.Time - (t.EndTime * loopCount);
|
float currentTime = t.Time - (t.EndTime * loopCount);
|
||||||
|
|
||||||
float normalizedTime = currentTime / t.Animation.Duration;
|
float normalizedTime = currentTime / t.Animation.Duration;
|
||||||
|
|
||||||
lineRect.x = barRect.x + (width * normalizedTime) - 0.5f;
|
lineRect.x = barRect.x + (width * normalizedTime) - 0.5f;
|
||||||
lineRect.width = 2;
|
lineRect.width = 2;
|
||||||
|
|
||||||
GUI.color = Color.red;
|
GUI.color = Color.red;
|
||||||
GUI.DrawTexture(lineRect, EditorGUIUtility.whiteTexture);
|
GUI.DrawTexture(lineRect, EditorGUIUtility.whiteTexture);
|
||||||
GUI.color = Color.white;
|
GUI.color = Color.white;
|
||||||
|
|
||||||
for (int i = 0; i < m_animEvents.Count; i++) {
|
for (int i = 0; i < m_animEvents.Count; i++) {
|
||||||
//TODO: Tooltip
|
//TODO: Tooltip
|
||||||
//Spine.Event spev = animEvents[i];
|
//Spine.Event spev = animEvents[i];
|
||||||
|
|
||||||
float fr = m_animEventFrames[i];
|
float fr = m_animEventFrames[i];
|
||||||
|
|
||||||
Rect evRect = new Rect(barRect);
|
Rect evRect = new Rect(barRect);
|
||||||
evRect.x = Mathf.Clamp(((fr / t.Animation.Duration) * width) - (SpineEditorUtilities.Icons._event.width / 2), barRect.x, float.MaxValue);
|
evRect.x = Mathf.Clamp(((fr / t.Animation.Duration) * width) - (SpineEditorUtilities.Icons._event.width / 2), barRect.x, float.MaxValue);
|
||||||
evRect.width = SpineEditorUtilities.Icons._event.width;
|
evRect.width = SpineEditorUtilities.Icons._event.width;
|
||||||
evRect.height = SpineEditorUtilities.Icons._event.height;
|
evRect.height = SpineEditorUtilities.Icons._event.height;
|
||||||
evRect.y += SpineEditorUtilities.Icons._event.height;
|
evRect.y += SpineEditorUtilities.Icons._event.height;
|
||||||
GUI.DrawTexture(evRect, SpineEditorUtilities.Icons._event);
|
GUI.DrawTexture(evRect, SpineEditorUtilities.Icons._event);
|
||||||
|
|
||||||
|
|
||||||
//TODO: Tooltip
|
//TODO: Tooltip
|
||||||
/*
|
/*
|
||||||
UnityEngine.Event ev = UnityEngine.Event.current;
|
UnityEngine.Event ev = UnityEngine.Event.current;
|
||||||
@ -500,24 +678,24 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseScroll (Rect position) {
|
void MouseScroll(Rect position) {
|
||||||
UnityEngine.Event current = UnityEngine.Event.current;
|
UnityEngine.Event current = UnityEngine.Event.current;
|
||||||
int controlID = GUIUtility.GetControlID(sliderHash, FocusType.Passive);
|
int controlID = GUIUtility.GetControlID(sliderHash, FocusType.Passive);
|
||||||
|
|
||||||
switch (current.GetTypeForControl(controlID)) {
|
switch (current.GetTypeForControl(controlID)) {
|
||||||
case EventType.ScrollWheel:
|
case EventType.ScrollWheel:
|
||||||
if (position.Contains(current.mousePosition)) {
|
if (position.Contains(current.mousePosition)) {
|
||||||
|
|
||||||
m_orthoGoal += current.delta.y * ((SkeletonDataAsset)target).scale * 10;
|
m_orthoGoal += current.delta.y * ((SkeletonDataAsset)target).scale * 10;
|
||||||
GUIUtility.hotControl = controlID;
|
GUIUtility.hotControl = controlID;
|
||||||
current.Use();
|
current.Use();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Implement preview panning
|
//TODO: Implement preview panning
|
||||||
/*
|
/*
|
||||||
static Vector2 Drag2D(Vector2 scrollPosition, Rect position)
|
static Vector2 Drag2D(Vector2 scrollPosition, Rect position)
|
||||||
@ -559,45 +737,45 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
return scrollPosition;
|
return scrollPosition;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public override GUIContent GetPreviewTitle () {
|
public override GUIContent GetPreviewTitle() {
|
||||||
return new GUIContent("Preview");
|
return new GUIContent("Preview");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnPreviewSettings () {
|
public override void OnPreviewSettings() {
|
||||||
if (!m_initialized) {
|
if (!m_initialized) {
|
||||||
GUILayout.HorizontalSlider(0, 0, 2, GUILayout.MaxWidth(64));
|
GUILayout.HorizontalSlider(0, 0, 2, GUILayout.MaxWidth(64));
|
||||||
} else {
|
} else {
|
||||||
float speed = GUILayout.HorizontalSlider(m_skeletonAnimation.timeScale, 0, 2, GUILayout.MaxWidth(64));
|
float speed = GUILayout.HorizontalSlider(m_skeletonAnimation.timeScale, 0, 2, GUILayout.MaxWidth(64));
|
||||||
|
|
||||||
//snap to nearest 0.25
|
//snap to nearest 0.25
|
||||||
float y = speed / 0.25f;
|
float y = speed / 0.25f;
|
||||||
int q = Mathf.RoundToInt(y);
|
int q = Mathf.RoundToInt(y);
|
||||||
speed = q * 0.25f;
|
speed = q * 0.25f;
|
||||||
|
|
||||||
m_skeletonAnimation.timeScale = speed;
|
m_skeletonAnimation.timeScale = speed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Fix first-import error
|
//TODO: Fix first-import error
|
||||||
//TODO: Update preview without thumbnail
|
//TODO: Update preview without thumbnail
|
||||||
public override Texture2D RenderStaticPreview (string assetPath, UnityEngine.Object[] subAssets, int width, int height) {
|
public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height) {
|
||||||
Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
||||||
|
|
||||||
this.InitPreview();
|
this.InitPreview();
|
||||||
|
|
||||||
if (this.m_previewUtility.m_Camera == null)
|
if (this.m_previewUtility.m_Camera == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
m_requireRefresh = true;
|
m_requireRefresh = true;
|
||||||
this.DoRenderPreview(false);
|
this.DoRenderPreview(false);
|
||||||
AdjustCameraGoals(false);
|
AdjustCameraGoals(false);
|
||||||
|
|
||||||
this.m_previewUtility.m_Camera.orthographicSize = m_orthoGoal / 2;
|
this.m_previewUtility.m_Camera.orthographicSize = m_orthoGoal / 2;
|
||||||
this.m_previewUtility.m_Camera.transform.position = m_posGoal;
|
this.m_previewUtility.m_Camera.transform.position = m_posGoal;
|
||||||
this.m_previewUtility.BeginStaticPreview(new Rect(0, 0, width, height));
|
this.m_previewUtility.BeginStaticPreview(new Rect(0, 0, width, height));
|
||||||
this.DoRenderPreview(false);
|
this.DoRenderPreview(false);
|
||||||
|
|
||||||
//TODO: Figure out why this is throwing errors on first attempt
|
//TODO: Figure out why this is throwing errors on first attempt
|
||||||
// if(m_previewUtility != null){
|
// if(m_previewUtility != null){
|
||||||
// Handles.SetCamera(this.m_previewUtility.m_Camera);
|
// Handles.SetCamera(this.m_previewUtility.m_Camera);
|
||||||
|
|||||||
@ -33,7 +33,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
[CustomEditor(typeof(SkeletonRenderer))]
|
[CustomEditor(typeof(SkeletonRenderer))]
|
||||||
public class SkeletonRendererInspector : Editor {
|
public class SkeletonRendererInspector : Editor {
|
||||||
protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles;
|
protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, submeshSeparators;
|
||||||
|
|
||||||
protected virtual void OnEnable () {
|
protected virtual void OnEnable () {
|
||||||
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
||||||
@ -42,6 +42,7 @@ public class SkeletonRendererInspector : Editor {
|
|||||||
tangents = serializedObject.FindProperty("calculateTangents");
|
tangents = serializedObject.FindProperty("calculateTangents");
|
||||||
meshes = serializedObject.FindProperty("renderMeshes");
|
meshes = serializedObject.FindProperty("renderMeshes");
|
||||||
immutableTriangles = serializedObject.FindProperty("immutableTriangles");
|
immutableTriangles = serializedObject.FindProperty("immutableTriangles");
|
||||||
|
submeshSeparators = serializedObject.FindProperty("submeshSeparators");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void gui () {
|
protected virtual void gui () {
|
||||||
@ -52,8 +53,11 @@ public class SkeletonRendererInspector : Editor {
|
|||||||
float reloadWidth = GUI.skin.label.CalcSize(new GUIContent("Reload")).x + 20;
|
float reloadWidth = GUI.skin.label.CalcSize(new GUIContent("Reload")).x + 20;
|
||||||
if (GUILayout.Button("Reload", GUILayout.Width(reloadWidth))) {
|
if (GUILayout.Button("Reload", GUILayout.Width(reloadWidth))) {
|
||||||
if (component.skeletonDataAsset != null) {
|
if (component.skeletonDataAsset != null) {
|
||||||
if (component.skeletonDataAsset.atlasAsset != null)
|
foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) {
|
||||||
component.skeletonDataAsset.atlasAsset.Reset();
|
if (aa != null)
|
||||||
|
aa.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
component.skeletonDataAsset.Reset();
|
component.skeletonDataAsset.Reset();
|
||||||
}
|
}
|
||||||
component.Reset();
|
component.Reset();
|
||||||
@ -92,6 +96,7 @@ public class SkeletonRendererInspector : Editor {
|
|||||||
new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility"));
|
new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility"));
|
||||||
EditorGUILayout.PropertyField(normals);
|
EditorGUILayout.PropertyField(normals);
|
||||||
EditorGUILayout.PropertyField(tangents);
|
EditorGUILayout.PropertyField(tangents);
|
||||||
|
EditorGUILayout.PropertyField(submeshSeparators, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void OnInspectorGUI () {
|
override public void OnInspectorGUI () {
|
||||||
|
|||||||
456
spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
Normal file
456
spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Spine;
|
||||||
|
|
||||||
|
|
||||||
|
public struct SpineDrawerValuePair {
|
||||||
|
public string str;
|
||||||
|
public SerializedProperty property;
|
||||||
|
|
||||||
|
public SpineDrawerValuePair(string val, SerializedProperty property) {
|
||||||
|
this.str = val;
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomPropertyDrawer(typeof(SpineSlot))]
|
||||||
|
public class SpineSlotDrawer : PropertyDrawer {
|
||||||
|
SkeletonDataAsset skeletonDataAsset;
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
||||||
|
if (property.propertyType != SerializedPropertyType.String) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpineSlot attrib = (SpineSlot)attribute;
|
||||||
|
|
||||||
|
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
|
||||||
|
|
||||||
|
if (skeletonDataAssetProperty != null) {
|
||||||
|
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
|
||||||
|
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
|
||||||
|
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
if (renderer != null)
|
||||||
|
skeletonDataAsset = renderer.skeletonDataAsset;
|
||||||
|
} else {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (property.serializedObject.targetObject is Component) {
|
||||||
|
var component = (Component)property.serializedObject.targetObject;
|
||||||
|
if (component.GetComponent<SkeletonRenderer>() != null) {
|
||||||
|
var skeletonRenderer = component.GetComponent<SkeletonRenderer>();
|
||||||
|
skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skeletonDataAsset == null) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
|
||||||
|
if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
|
||||||
|
Selector(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector(SerializedProperty property) {
|
||||||
|
SpineSlot attrib = (SpineSlot)attribute;
|
||||||
|
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
|
||||||
|
if (data == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GenericMenu menu = new GenericMenu();
|
||||||
|
|
||||||
|
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
|
||||||
|
menu.AddSeparator("");
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Slots.Count; i++) {
|
||||||
|
string name = data.Slots[i].Name;
|
||||||
|
if (name.StartsWith(attrib.startsWith))
|
||||||
|
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.ShowAsContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSelect(object val) {
|
||||||
|
var pair = (SpineDrawerValuePair)val;
|
||||||
|
pair.property.stringValue = pair.str;
|
||||||
|
pair.property.serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomPropertyDrawer(typeof(SpineSkin))]
|
||||||
|
public class SpineSkinDrawer : PropertyDrawer {
|
||||||
|
SkeletonDataAsset skeletonDataAsset;
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
||||||
|
if (property.propertyType != SerializedPropertyType.String) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpineSkin attrib = (SpineSkin)attribute;
|
||||||
|
|
||||||
|
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
|
||||||
|
|
||||||
|
if (skeletonDataAssetProperty != null) {
|
||||||
|
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
|
||||||
|
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
|
||||||
|
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
if (renderer != null)
|
||||||
|
skeletonDataAsset = renderer.skeletonDataAsset;
|
||||||
|
} else {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (property.serializedObject.targetObject is Component) {
|
||||||
|
var component = (Component)property.serializedObject.targetObject;
|
||||||
|
if (component.GetComponent<SkeletonRenderer>() != null) {
|
||||||
|
var skeletonRenderer = component.GetComponent<SkeletonRenderer>();
|
||||||
|
skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skeletonDataAsset == null) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
|
||||||
|
if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
|
||||||
|
Selector(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector(SerializedProperty property) {
|
||||||
|
SpineSkin attrib = (SpineSkin)attribute;
|
||||||
|
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
|
||||||
|
if (data == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GenericMenu menu = new GenericMenu();
|
||||||
|
|
||||||
|
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
|
||||||
|
menu.AddSeparator("");
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Skins.Count; i++) {
|
||||||
|
string name = data.Skins[i].Name;
|
||||||
|
if (name.StartsWith(attrib.startsWith))
|
||||||
|
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.ShowAsContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSelect(object val) {
|
||||||
|
var pair = (SpineDrawerValuePair)val;
|
||||||
|
pair.property.stringValue = pair.str;
|
||||||
|
pair.property.serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomPropertyDrawer(typeof(SpineAtlasRegion))]
|
||||||
|
public class SpineAtlasRegionDrawer : PropertyDrawer {
|
||||||
|
Component component;
|
||||||
|
SerializedProperty atlasProp;
|
||||||
|
|
||||||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
||||||
|
if (property.propertyType != SerializedPropertyType.String) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component = (Component)property.serializedObject.targetObject;
|
||||||
|
|
||||||
|
if (component != null)
|
||||||
|
atlasProp = property.serializedObject.FindProperty("atlasAsset");
|
||||||
|
else
|
||||||
|
atlasProp = null;
|
||||||
|
|
||||||
|
|
||||||
|
if (atlasProp == null) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Must have AtlasAsset variable!");
|
||||||
|
return;
|
||||||
|
} else if (atlasProp.objectReferenceValue == null) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Atlas variable must not be null!");
|
||||||
|
return;
|
||||||
|
} else if (atlasProp.objectReferenceValue.GetType() != typeof(AtlasAsset)) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Atlas variable must be of type AtlasAsset!");
|
||||||
|
}
|
||||||
|
|
||||||
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
|
||||||
|
if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
|
||||||
|
Selector(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector(SerializedProperty property) {
|
||||||
|
GenericMenu menu = new GenericMenu();
|
||||||
|
AtlasAsset atlasAsset = (AtlasAsset)atlasProp.objectReferenceValue;
|
||||||
|
Atlas atlas = atlasAsset.GetAtlas();
|
||||||
|
FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic);
|
||||||
|
List<AtlasRegion> regions = (List<AtlasRegion>)field.GetValue(atlas);
|
||||||
|
|
||||||
|
for (int i = 0; i < regions.Count; i++) {
|
||||||
|
string name = regions[i].name;
|
||||||
|
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menu.ShowAsContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSelect(object val) {
|
||||||
|
var pair = (SpineDrawerValuePair)val;
|
||||||
|
pair.property.stringValue = pair.str;
|
||||||
|
pair.property.serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomPropertyDrawer(typeof(SpineAnimation))]
|
||||||
|
public class SpineAnimationDrawer : PropertyDrawer {
|
||||||
|
SkeletonDataAsset skeletonDataAsset;
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
||||||
|
|
||||||
|
|
||||||
|
if (property.propertyType != SerializedPropertyType.String) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpineAnimation attrib = (SpineAnimation)attribute;
|
||||||
|
|
||||||
|
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
|
||||||
|
|
||||||
|
if (skeletonDataAssetProperty != null) {
|
||||||
|
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
|
||||||
|
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
|
||||||
|
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
if (renderer != null)
|
||||||
|
skeletonDataAsset = renderer.skeletonDataAsset;
|
||||||
|
} else {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (property.serializedObject.targetObject is Component) {
|
||||||
|
var component = (Component)property.serializedObject.targetObject;
|
||||||
|
if (component.GetComponent<SkeletonRenderer>() != null) {
|
||||||
|
var skeletonRenderer = component.GetComponent<SkeletonRenderer>();
|
||||||
|
skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skeletonDataAsset == null) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
|
||||||
|
if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
|
||||||
|
Selector(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector(SerializedProperty property) {
|
||||||
|
|
||||||
|
SpineAnimation attrib = (SpineAnimation)attribute;
|
||||||
|
|
||||||
|
GenericMenu menu = new GenericMenu();
|
||||||
|
|
||||||
|
var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations;
|
||||||
|
for (int i = 0; i < animations.Count; i++) {
|
||||||
|
string name = animations[i].Name;
|
||||||
|
if (name.StartsWith(attrib.startsWith))
|
||||||
|
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.ShowAsContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSelect(object val) {
|
||||||
|
var pair = (SpineDrawerValuePair)val;
|
||||||
|
pair.property.stringValue = pair.str;
|
||||||
|
pair.property.serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomPropertyDrawer(typeof(SpineAttachment))]
|
||||||
|
public class SpineAttachmentDrawer : PropertyDrawer {
|
||||||
|
|
||||||
|
SkeletonDataAsset skeletonDataAsset;
|
||||||
|
SkeletonRenderer skeletonRenderer;
|
||||||
|
|
||||||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
||||||
|
|
||||||
|
if (property.propertyType != SerializedPropertyType.String) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpineAttachment attrib = (SpineAttachment)attribute;
|
||||||
|
|
||||||
|
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
|
||||||
|
|
||||||
|
if (skeletonDataAssetProperty != null) {
|
||||||
|
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
|
||||||
|
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
|
||||||
|
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
|
||||||
|
if (renderer != null)
|
||||||
|
skeletonDataAsset = renderer.skeletonDataAsset;
|
||||||
|
else {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "No SkeletonRenderer");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (property.serializedObject.targetObject is Component) {
|
||||||
|
var component = (Component)property.serializedObject.targetObject;
|
||||||
|
if (component.GetComponent<SkeletonRenderer>() != null) {
|
||||||
|
skeletonRenderer = component.GetComponent<SkeletonRenderer>();
|
||||||
|
skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skeletonDataAsset == null && skeletonRenderer == null) {
|
||||||
|
EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset or SkeletonRenderer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
|
||||||
|
if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
|
||||||
|
Selector(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector(SerializedProperty property) {
|
||||||
|
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
|
||||||
|
|
||||||
|
if (data == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpineAttachment attrib = (SpineAttachment)attribute;
|
||||||
|
|
||||||
|
List<Skin> validSkins = new List<Skin>();
|
||||||
|
|
||||||
|
if (skeletonRenderer != null && attrib.currentSkinOnly) {
|
||||||
|
if (skeletonRenderer.skeleton.Skin != null)
|
||||||
|
validSkins.Add(skeletonRenderer.skeleton.Skin);
|
||||||
|
} else {
|
||||||
|
foreach (Skin skin in data.Skins) {
|
||||||
|
if (skin != null)
|
||||||
|
validSkins.Add(skin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericMenu menu = new GenericMenu();
|
||||||
|
List<string> attachmentNames = new List<string>();
|
||||||
|
string prefix = "";
|
||||||
|
|
||||||
|
if (skeletonRenderer != null && attrib.currentSkinOnly)
|
||||||
|
menu.AddDisabledItem(new GUIContent(skeletonRenderer.gameObject.name + " (SkeletonRenderer)"));
|
||||||
|
else
|
||||||
|
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
|
||||||
|
menu.AddSeparator("");
|
||||||
|
|
||||||
|
menu.AddItem(new GUIContent("Null"), property.stringValue == "", HandleSelect, new SpineDrawerValuePair("", property));
|
||||||
|
menu.AddSeparator("");
|
||||||
|
|
||||||
|
Skin defaultSkin = data.Skins[0];
|
||||||
|
|
||||||
|
SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotSource);
|
||||||
|
string slotMatch = "";
|
||||||
|
if (slotProperty != null) {
|
||||||
|
if (slotProperty.propertyType == SerializedPropertyType.String) {
|
||||||
|
slotMatch = slotProperty.stringValue.ToLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Skin skin in validSkins) {
|
||||||
|
string skinPrefix = skin.Name + "/";
|
||||||
|
|
||||||
|
if (validSkins.Count > 1)
|
||||||
|
prefix = skinPrefix;
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Slots.Count; i++) {
|
||||||
|
if (slotMatch.Length > 0 && data.Slots[i].Name.ToLower().Contains(slotMatch) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
attachmentNames.Clear();
|
||||||
|
skin.FindNamesForSlot(i, attachmentNames);
|
||||||
|
if (skin != defaultSkin)
|
||||||
|
defaultSkin.FindNamesForSlot(i, attachmentNames);
|
||||||
|
|
||||||
|
for (int a = 0; a < attachmentNames.Count; a++) {
|
||||||
|
string attachmentPath = attachmentNames[a];
|
||||||
|
string menuPath = prefix + data.Slots[i].Name + "/" + attachmentPath;
|
||||||
|
string name = attachmentNames[a];
|
||||||
|
|
||||||
|
if (attrib.returnFullPath)
|
||||||
|
name = skin.Name + "/" + data.Slots[i].Name + "/" + attachmentPath;
|
||||||
|
menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menu.ShowAsContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSelect(object val) {
|
||||||
|
var pair = (SpineDrawerValuePair)val;
|
||||||
|
pair.property.stringValue = pair.str;
|
||||||
|
pair.property.serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f2de282d583d4a641bf1c349f0a3eef9
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
@ -39,6 +39,8 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using Spine;
|
using Spine;
|
||||||
|
|
||||||
[InitializeOnLoad]
|
[InitializeOnLoad]
|
||||||
@ -51,10 +53,12 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
public static Texture2D poseBones;
|
public static Texture2D poseBones;
|
||||||
public static Texture2D boneNib;
|
public static Texture2D boneNib;
|
||||||
public static Texture2D slot;
|
public static Texture2D slot;
|
||||||
|
public static Texture2D slotRoot;
|
||||||
public static Texture2D skinPlaceholder;
|
public static Texture2D skinPlaceholder;
|
||||||
public static Texture2D image;
|
public static Texture2D image;
|
||||||
public static Texture2D boundingBox;
|
public static Texture2D boundingBox;
|
||||||
public static Texture2D mesh;
|
public static Texture2D mesh;
|
||||||
|
public static Texture2D weights;
|
||||||
public static Texture2D skin;
|
public static Texture2D skin;
|
||||||
public static Texture2D skinsRoot;
|
public static Texture2D skinsRoot;
|
||||||
public static Texture2D animation;
|
public static Texture2D animation;
|
||||||
@ -78,7 +82,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
new Vector3(0.1f, 0.1f, 0)
|
new Vector3(0.1f, 0.1f, 0)
|
||||||
};
|
};
|
||||||
_boneMesh.uv = new Vector2[4];
|
_boneMesh.uv = new Vector2[4];
|
||||||
_boneMesh.triangles = new int[6]{0,1,2,2,3,0};
|
_boneMesh.triangles = new int[6] { 0, 1, 2, 2, 3, 0 };
|
||||||
_boneMesh.RecalculateBounds();
|
_boneMesh.RecalculateBounds();
|
||||||
_boneMesh.RecalculateNormals();
|
_boneMesh.RecalculateNormals();
|
||||||
}
|
}
|
||||||
@ -108,17 +112,19 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
|
|
||||||
internal static Material _boneMaterial;
|
internal static Material _boneMaterial;
|
||||||
|
|
||||||
public static void Initialize () {
|
public static void Initialize() {
|
||||||
skeleton = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skeleton.png");
|
skeleton = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skeleton.png");
|
||||||
nullBone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-null.png");
|
nullBone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-null.png");
|
||||||
bone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-bone.png");
|
bone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-bone.png");
|
||||||
poseBones = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-poseBones.png");
|
poseBones = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-poseBones.png");
|
||||||
boneNib = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boneNib.png");
|
boneNib = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boneNib.png");
|
||||||
slot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slot.png");
|
slot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slot.png");
|
||||||
|
slotRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slotRoot.png");
|
||||||
skinPlaceholder = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
|
skinPlaceholder = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
|
||||||
image = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-image.png");
|
image = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-image.png");
|
||||||
boundingBox = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boundingBox.png");
|
boundingBox = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boundingBox.png");
|
||||||
mesh = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-mesh.png");
|
mesh = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-mesh.png");
|
||||||
|
weights = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-weights.png");
|
||||||
skin = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
|
skin = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
|
||||||
skinsRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinsRoot.png");
|
skinsRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinsRoot.png");
|
||||||
animation = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-animation.png");
|
animation = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-animation.png");
|
||||||
@ -140,12 +146,12 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
public static float defaultScale = 0.01f;
|
public static float defaultScale = 0.01f;
|
||||||
public static float defaultMix = 0.2f;
|
public static float defaultMix = 0.2f;
|
||||||
public static string defaultShader = "Spine/Skeleton";
|
public static string defaultShader = "Spine/Skeleton";
|
||||||
|
|
||||||
static SpineEditorUtilities () {
|
static SpineEditorUtilities() {
|
||||||
DirectoryInfo rootDir = new DirectoryInfo(Application.dataPath);
|
DirectoryInfo rootDir = new DirectoryInfo(Application.dataPath);
|
||||||
FileInfo[] files = rootDir.GetFiles("SpineEditorUtilities.cs", SearchOption.AllDirectories);
|
FileInfo[] files = rootDir.GetFiles("SpineEditorUtilities.cs", SearchOption.AllDirectories);
|
||||||
editorPath = Path.GetDirectoryName(files[0].FullName.Replace("\\", "/").Replace(Application.dataPath, "Assets"));
|
editorPath = Path.GetDirectoryName(files[0].FullName.Replace("\\", "/").Replace(Application.dataPath, "Assets"));
|
||||||
editorGUIPath = editorPath + "/GUI";
|
editorGUIPath = editorPath + "/GUI";
|
||||||
|
|
||||||
Icons.Initialize();
|
Icons.Initialize();
|
||||||
|
|
||||||
@ -158,7 +164,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
HierarchyWindowChanged();
|
HierarchyWindowChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HierarchyWindowChanged () {
|
static void HierarchyWindowChanged() {
|
||||||
skeletonRendererTable.Clear();
|
skeletonRendererTable.Clear();
|
||||||
skeletonUtilityBoneTable.Clear();
|
skeletonUtilityBoneTable.Clear();
|
||||||
|
|
||||||
@ -172,122 +178,299 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
skeletonUtilityBoneTable.Add(b.gameObject.GetInstanceID(), b);
|
skeletonUtilityBoneTable.Add(b.gameObject.GetInstanceID(), b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HierarchyWindowItemOnGUI (int instanceId, Rect selectionRect) {
|
static void HierarchyWindowItemOnGUI(int instanceId, Rect selectionRect) {
|
||||||
if (skeletonRendererTable.ContainsKey(instanceId)) {
|
if (skeletonRendererTable.ContainsKey(instanceId)) {
|
||||||
Rect r = new Rect(selectionRect);
|
Rect r = new Rect(selectionRect);
|
||||||
r.x = r.width - 15;
|
r.x = r.width - 15;
|
||||||
r.width = 15;
|
r.width = 15;
|
||||||
|
|
||||||
GUI.Label(r, Icons.spine);
|
GUI.Label(r, Icons.spine);
|
||||||
} else if (skeletonUtilityBoneTable.ContainsKey(instanceId)) {
|
} else if (skeletonUtilityBoneTable.ContainsKey(instanceId)) {
|
||||||
Rect r = new Rect(selectionRect);
|
Rect r = new Rect(selectionRect);
|
||||||
r.x -= 26;
|
r.x -= 26;
|
||||||
|
|
||||||
if (skeletonUtilityBoneTable[instanceId] != null) {
|
if (skeletonUtilityBoneTable[instanceId] != null) {
|
||||||
if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0)
|
if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0)
|
||||||
r.x += 13;
|
r.x += 13;
|
||||||
|
|
||||||
r.y += 2;
|
|
||||||
|
|
||||||
r.width = 13;
|
r.y += 2;
|
||||||
r.height = 13;
|
|
||||||
|
|
||||||
if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) {
|
r.width = 13;
|
||||||
GUI.DrawTexture(r, Icons.bone);
|
r.height = 13;
|
||||||
} else {
|
|
||||||
GUI.DrawTexture(r, Icons.poseBones);
|
if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) {
|
||||||
}
|
GUI.DrawTexture(r, Icons.bone);
|
||||||
|
} else {
|
||||||
|
GUI.DrawTexture(r, Icons.poseBones);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[MenuItem("Assets/Spine/Ingest")]
|
|
||||||
static void IngestSpineProjectFromSelection () {
|
|
||||||
TextAsset spineJson = null;
|
|
||||||
TextAsset atlasText = null;
|
|
||||||
|
|
||||||
List<TextAsset> spineJsonList = new List<TextAsset>();
|
|
||||||
|
|
||||||
foreach (UnityEngine.Object o in Selection.objects) {
|
|
||||||
if (o.GetType() != typeof(TextAsset))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
string fileName = Path.GetFileName(AssetDatabase.GetAssetPath(o));
|
|
||||||
|
|
||||||
if (fileName.EndsWith(".json"))
|
|
||||||
spineJson = (TextAsset)o;
|
|
||||||
else if (fileName.EndsWith(".atlas.txt"))
|
|
||||||
atlasText = (TextAsset)o;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spineJson == null) {
|
|
||||||
EditorUtility.DisplayDialog("Error!", "Spine JSON file not found in selection!", "OK");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
|
||||||
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
|
|
||||||
|
|
||||||
if (atlasText == null) {
|
|
||||||
string atlasPath = assetPath + "/" + primaryName + ".atlas.txt";
|
|
||||||
atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AtlasAsset atlasAsset = IngestSpineAtlas(atlasText);
|
|
||||||
|
|
||||||
IngestSpineProject(spineJson, atlasAsset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
|
|
||||||
//debug
|
|
||||||
// return;
|
|
||||||
|
|
||||||
AtlasAsset sharedAtlas = null;
|
static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
|
||||||
|
|
||||||
System.Array.Sort<string>(imported);
|
List<string> atlasPaths = new List<string>();
|
||||||
|
List<string> imagePaths = new List<string>();
|
||||||
|
List<string> skeletonPaths = new List<string>();
|
||||||
|
|
||||||
foreach (string str in imported) {
|
foreach (string str in imported) {
|
||||||
if (Path.GetExtension(str).ToLower() == ".json") {
|
string extension = Path.GetExtension(str).ToLower();
|
||||||
TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset));
|
switch (extension) {
|
||||||
if (IsSpineJSON(spineJson)) {
|
case ".txt":
|
||||||
|
if (str.EndsWith(".atlas.txt")) {
|
||||||
if (sharedAtlas != null) {
|
atlasPaths.Add(str);
|
||||||
string spinePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
|
|
||||||
string atlasPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(sharedAtlas));
|
|
||||||
if (spinePath != atlasPath)
|
|
||||||
sharedAtlas = null;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
SkeletonDataAsset data = AutoIngestSpineProject(spineJson, sharedAtlas);
|
case ".png":
|
||||||
if (data == null)
|
case ".jpg":
|
||||||
continue;
|
imagePaths.Add(str);
|
||||||
|
break;
|
||||||
sharedAtlas = data.atlasAsset;
|
case ".json":
|
||||||
|
TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset));
|
||||||
|
if (IsSpineJSON(spineJson)) {
|
||||||
string dir = Path.GetDirectoryName(Path.GetDirectoryName(AssetDatabase.GetAssetPath(data)));
|
skeletonPaths.Add(str);
|
||||||
string prefabPath = Path.Combine(dir, data.skeletonJSON.name + ".prefab").Replace("\\", "/");
|
|
||||||
|
|
||||||
if (File.Exists(prefabPath) == false) {
|
|
||||||
SkeletonAnimation anim = SpawnAnimatedSkeleton(data);
|
|
||||||
PrefabUtility.CreatePrefab(prefabPath, anim.gameObject, ReplacePrefabOptions.ReplaceNameBased);
|
|
||||||
if (EditorApplication.isPlaying)
|
|
||||||
GameObject.Destroy(anim.gameObject);
|
|
||||||
else
|
|
||||||
GameObject.DestroyImmediate(anim.gameObject);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<AtlasAsset> atlases = new List<AtlasAsset>();
|
||||||
|
|
||||||
|
//import atlases first
|
||||||
|
foreach (string ap in atlasPaths) {
|
||||||
|
TextAsset atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(ap, typeof(TextAsset));
|
||||||
|
AtlasAsset atlas = IngestSpineAtlas(atlasText);
|
||||||
|
atlases.Add(atlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
//import skeletons and match them with atlases
|
||||||
|
bool abortSkeletonImport = false;
|
||||||
|
foreach (string sp in skeletonPaths) {
|
||||||
|
string dir = Path.GetDirectoryName(sp);
|
||||||
|
var localAtlases = FindAtlasesAtPath(dir);
|
||||||
|
var requiredPaths = GetRequiredAtlasRegions(sp);
|
||||||
|
var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases);
|
||||||
|
|
||||||
|
if (atlasMatch != null) {
|
||||||
|
IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch);
|
||||||
|
} else {
|
||||||
|
bool resolved = false;
|
||||||
|
while (!resolved) {
|
||||||
|
int result = EditorUtility.DisplayDialogComplex("Skeleton JSON Import Error!", "Could not find matching AtlasAsset for " + Path.GetFileNameWithoutExtension(sp), "Select", "Skip", "Abort");
|
||||||
|
switch (result) {
|
||||||
|
case -1:
|
||||||
|
Debug.Log("Select Atlas");
|
||||||
|
AtlasAsset selectedAtlas = GetAtlasDialog(Path.GetDirectoryName(sp));
|
||||||
|
if (selectedAtlas != null) {
|
||||||
|
localAtlases.Clear();
|
||||||
|
localAtlases.Add(selectedAtlas);
|
||||||
|
atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases);
|
||||||
|
if (atlasMatch != null) {
|
||||||
|
resolved = true;
|
||||||
|
IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
var atlasList = MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(sp), Path.GetFileNameWithoutExtension(sp));
|
||||||
|
|
||||||
|
if (atlasList != null)
|
||||||
|
IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasList.ToArray());
|
||||||
|
|
||||||
|
resolved = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
Debug.Log("Skipped importing: " + Path.GetFileName(sp));
|
||||||
|
resolved = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
//abort
|
||||||
|
abortSkeletonImport = true;
|
||||||
|
resolved = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortSkeletonImport)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: any post processing of images
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<AtlasAsset> MultiAtlasDialog(List<string> requiredPaths, string initialDirectory, string header = "") {
|
||||||
|
|
||||||
|
List<AtlasAsset> atlasAssets = new List<AtlasAsset>();
|
||||||
|
|
||||||
|
bool resolved = false;
|
||||||
|
string lastAtlasPath = initialDirectory;
|
||||||
|
while (!resolved) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine(header);
|
||||||
|
sb.AppendLine("Atlases:");
|
||||||
|
if (atlasAssets.Count == 0) {
|
||||||
|
sb.AppendLine("\t--none--");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < atlasAssets.Count; i++) {
|
||||||
|
sb.AppendLine("\t" + atlasAssets[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
sb.AppendLine("Missing Regions:");
|
||||||
|
|
||||||
|
List<string> missingRegions = new List<string>(requiredPaths);
|
||||||
|
|
||||||
|
foreach (var atlasAsset in atlasAssets) {
|
||||||
|
var atlas = atlasAsset.GetAtlas();
|
||||||
|
for (int i = 0; i < missingRegions.Count; i++) {
|
||||||
|
if (atlas.FindRegion(missingRegions[i]) != null) {
|
||||||
|
missingRegions.RemoveAt(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingRegions.Count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < missingRegions.Count; i++) {
|
||||||
|
sb.AppendLine("\t" + missingRegions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = EditorUtility.DisplayDialogComplex("Atlas Selection", sb.ToString(), "Select", "Finish", "Abort");
|
||||||
|
|
||||||
|
switch(result){
|
||||||
|
case 0:
|
||||||
|
AtlasAsset selectedAtlasAsset = GetAtlasDialog(lastAtlasPath);
|
||||||
|
if (selectedAtlasAsset != null) {
|
||||||
|
var atlas = selectedAtlasAsset.GetAtlas();
|
||||||
|
bool hasValidRegion = false;
|
||||||
|
foreach (string str in missingRegions) {
|
||||||
|
if (atlas.FindRegion(str) != null) {
|
||||||
|
hasValidRegion = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
atlasAssets.Add(selectedAtlasAsset);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
resolved = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
atlasAssets = null;
|
||||||
|
resolved = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return atlasAssets;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtlasAsset GetAtlasDialog(string dirPath) {
|
||||||
|
string path = EditorUtility.OpenFilePanel("Select AtlasAsset...", dirPath, "asset");
|
||||||
|
if (path == "")
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int subLen = Application.dataPath.Length - 6;
|
||||||
|
string assetRelativePath = path.Substring(subLen, path.Length - subLen).Replace("\\", "/");
|
||||||
|
|
||||||
|
Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAsset));
|
||||||
|
|
||||||
|
if (obj == null || obj.GetType() != typeof(AtlasAsset))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return (AtlasAsset)obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<string> GetRequiredAtlasRegions(string jsonPath) {
|
||||||
|
List<string> requiredPaths = new List<string>();
|
||||||
|
|
||||||
|
TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(jsonPath, typeof(TextAsset));
|
||||||
|
|
||||||
|
StringReader reader = new StringReader(spineJson.text);
|
||||||
|
var root = Json.Deserialize(reader) as Dictionary<string, object>;
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, object> entry in (Dictionary<string, object>)root["skins"]) {
|
||||||
|
foreach (KeyValuePair<string, object> slotEntry in (Dictionary<string, object>)entry.Value) {
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, object> attachmentEntry in ((Dictionary<string, object>)slotEntry.Value)) {
|
||||||
|
var data = ((Dictionary<string, object>)attachmentEntry.Value);
|
||||||
|
if (data.ContainsKey("path"))
|
||||||
|
requiredPaths.Add((string)data["path"]);
|
||||||
|
else if (data.ContainsKey("name"))
|
||||||
|
requiredPaths.Add((string)data["name"]);
|
||||||
|
else
|
||||||
|
requiredPaths.Add(attachmentEntry.Key);
|
||||||
|
//requiredPaths.Add((string)sdf["path"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return requiredPaths;
|
||||||
|
}
|
||||||
|
static AtlasAsset GetMatchingAtlas(List<string> requiredPaths, List<AtlasAsset> atlasAssets) {
|
||||||
|
AtlasAsset atlasAssetMatch = null;
|
||||||
|
|
||||||
|
foreach (AtlasAsset a in atlasAssets) {
|
||||||
|
Atlas atlas = a.GetAtlas();
|
||||||
|
bool failed = false;
|
||||||
|
foreach (string regionPath in requiredPaths) {
|
||||||
|
if (atlas.FindRegion(regionPath) == null) {
|
||||||
|
failed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!failed) {
|
||||||
|
atlasAssetMatch = a;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return atlasAssetMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsSpineJSON (TextAsset asset) {
|
static List<AtlasAsset> FindAtlasesAtPath(string path) {
|
||||||
|
List<AtlasAsset> arr = new List<AtlasAsset>();
|
||||||
|
|
||||||
|
DirectoryInfo dir = new DirectoryInfo(path);
|
||||||
|
FileInfo[] assetInfoArr = dir.GetFiles("*.asset");
|
||||||
|
|
||||||
|
int subLen = Application.dataPath.Length - 6;
|
||||||
|
|
||||||
|
foreach (var f in assetInfoArr) {
|
||||||
|
string assetRelativePath = f.FullName.Substring(subLen, f.FullName.Length - subLen).Replace("\\", "/");
|
||||||
|
|
||||||
|
Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAsset));
|
||||||
|
if (obj != null) {
|
||||||
|
arr.Add(obj as AtlasAsset);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsSpineJSON(TextAsset asset) {
|
||||||
object obj = Json.Deserialize(new StringReader(asset.text));
|
object obj = Json.Deserialize(new StringReader(asset.text));
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
Debug.LogError("Is not valid JSON");
|
Debug.LogError("Is not valid JSON");
|
||||||
@ -307,51 +490,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SkeletonDataAsset AutoIngestSpineProject (TextAsset spineJson, Object atlasSource = null) {
|
static AtlasAsset IngestSpineAtlas(TextAsset atlasText) {
|
||||||
TextAsset atlasText = null;
|
|
||||||
AtlasAsset atlasAsset = null;
|
|
||||||
|
|
||||||
if (atlasSource != null) {
|
|
||||||
if (atlasSource.GetType() == typeof(TextAsset)) {
|
|
||||||
atlasText = (TextAsset)atlasSource;
|
|
||||||
} else if (atlasSource.GetType() == typeof(AtlasAsset)) {
|
|
||||||
atlasAsset = (AtlasAsset)atlasSource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atlasText == null && atlasAsset == null) {
|
|
||||||
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
|
||||||
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
|
|
||||||
|
|
||||||
if (atlasText == null) {
|
|
||||||
string atlasPath = assetPath + "/" + primaryName + ".atlas.txt";
|
|
||||||
atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
|
|
||||||
|
|
||||||
if (atlasText == null) {
|
|
||||||
//can't find atlas, likely because using a shared atlas
|
|
||||||
bool abort = !EditorUtility.DisplayDialog("Atlas not Found", "Expecting " + spineJson.name + ".atlas\n" + "Press OK to select Atlas", "OK", "Abort");
|
|
||||||
if (abort) {
|
|
||||||
//do nothing, let it error later
|
|
||||||
} else {
|
|
||||||
string path = EditorUtility.OpenFilePanel("Find Atlas source...", Path.GetDirectoryName(Application.dataPath) + "/" + assetPath, "txt");
|
|
||||||
if (path != "") {
|
|
||||||
path = path.Replace("\\", "/");
|
|
||||||
path = path.Replace(Application.dataPath.Replace("\\", "/"), "Assets");
|
|
||||||
atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atlasAsset == null)
|
|
||||||
atlasAsset = IngestSpineAtlas(atlasText);
|
|
||||||
|
|
||||||
return IngestSpineProject(spineJson, atlasAsset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static AtlasAsset IngestSpineAtlas (TextAsset atlasText) {
|
|
||||||
if (atlasText == null) {
|
if (atlasText == null) {
|
||||||
Debug.LogWarning("Atlas source cannot be null!");
|
Debug.LogWarning("Atlas source cannot be null!");
|
||||||
return null;
|
return null;
|
||||||
@ -376,17 +515,17 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
|
|
||||||
string[] atlasLines = atlasStr.Split('\n');
|
string[] atlasLines = atlasStr.Split('\n');
|
||||||
List<string> pageFiles = new List<string>();
|
List<string> pageFiles = new List<string>();
|
||||||
for (int i = 0; i < atlasLines.Length-1; i++) {
|
for (int i = 0; i < atlasLines.Length - 1; i++) {
|
||||||
if (atlasLines[i].Length == 0)
|
if (atlasLines[i].Length == 0)
|
||||||
pageFiles.Add(atlasLines[i + 1]);
|
pageFiles.Add(atlasLines[i + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
atlasAsset.materials = new Material[pageFiles.Count];
|
atlasAsset.materials = new Material[pageFiles.Count];
|
||||||
|
|
||||||
for (int i = 0; i < pageFiles.Count; i++) {
|
for (int i = 0; i < pageFiles.Count; i++) {
|
||||||
string texturePath = assetPath + "/" + pageFiles[i];
|
string texturePath = assetPath + "/" + pageFiles[i];
|
||||||
Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
|
Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
|
||||||
|
|
||||||
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
||||||
texImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor;
|
texImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor;
|
||||||
texImporter.mipmapEnabled = false;
|
texImporter.mipmapEnabled = false;
|
||||||
@ -396,13 +535,13 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
EditorUtility.SetDirty(texImporter);
|
EditorUtility.SetDirty(texImporter);
|
||||||
AssetDatabase.ImportAsset(texturePath);
|
AssetDatabase.ImportAsset(texturePath);
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]);
|
string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]);
|
||||||
|
|
||||||
//because this looks silly
|
//because this looks silly
|
||||||
if (pageName == primaryName && pageFiles.Count == 1)
|
if (pageName == primaryName && pageFiles.Count == 1)
|
||||||
pageName = "Material";
|
pageName = "Material";
|
||||||
|
|
||||||
string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat";
|
string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat";
|
||||||
Material mat = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material));
|
Material mat = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material));
|
||||||
|
|
||||||
@ -410,12 +549,12 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
mat = new Material(Shader.Find(defaultShader));
|
mat = new Material(Shader.Find(defaultShader));
|
||||||
AssetDatabase.CreateAsset(mat, materialPath);
|
AssetDatabase.CreateAsset(mat, materialPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
mat.mainTexture = texture;
|
mat.mainTexture = texture;
|
||||||
EditorUtility.SetDirty(mat);
|
EditorUtility.SetDirty(mat);
|
||||||
|
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
atlasAsset.materials[i] = mat;
|
atlasAsset.materials[i] = mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,40 +568,41 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
return (AtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAsset));
|
return (AtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAsset));
|
||||||
}
|
}
|
||||||
|
|
||||||
static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, AtlasAsset atlasAsset = null) {
|
static SkeletonDataAsset IngestSpineProject(TextAsset spineJson, params AtlasAsset[] atlasAssets) {
|
||||||
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
||||||
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
|
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
|
||||||
string filePath = assetPath + "/" + primaryName + "_SkeletonData.asset";
|
string filePath = assetPath + "/" + primaryName + "_SkeletonData.asset";
|
||||||
|
|
||||||
if (spineJson != null && atlasAsset != null) {
|
if (spineJson != null && atlasAssets != null) {
|
||||||
|
|
||||||
SkeletonDataAsset skelDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset));
|
SkeletonDataAsset skelDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset));
|
||||||
if (skelDataAsset == null) {
|
if (skelDataAsset == null) {
|
||||||
skelDataAsset = SkeletonDataAsset.CreateInstance<SkeletonDataAsset>();
|
skelDataAsset = SkeletonDataAsset.CreateInstance<SkeletonDataAsset>();
|
||||||
skelDataAsset.atlasAsset = atlasAsset;
|
skelDataAsset.atlasAssets = atlasAssets;
|
||||||
skelDataAsset.skeletonJSON = spineJson;
|
skelDataAsset.skeletonJSON = spineJson;
|
||||||
skelDataAsset.fromAnimation = new string[0];
|
skelDataAsset.fromAnimation = new string[0];
|
||||||
skelDataAsset.toAnimation = new string[0];
|
skelDataAsset.toAnimation = new string[0];
|
||||||
skelDataAsset.duration = new float[0];
|
skelDataAsset.duration = new float[0];
|
||||||
skelDataAsset.defaultMix = defaultMix;
|
skelDataAsset.defaultMix = defaultMix;
|
||||||
skelDataAsset.scale = defaultScale;
|
skelDataAsset.scale = defaultScale;
|
||||||
|
|
||||||
AssetDatabase.CreateAsset(skelDataAsset, filePath);
|
AssetDatabase.CreateAsset(skelDataAsset, filePath);
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
} else {
|
} else {
|
||||||
|
skelDataAsset.atlasAssets = atlasAssets;
|
||||||
skelDataAsset.Reset();
|
skelDataAsset.Reset();
|
||||||
skelDataAsset.GetSkeletonData(true);
|
skelDataAsset.GetSkeletonData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return skelDataAsset;
|
return skelDataAsset;
|
||||||
} else {
|
} else {
|
||||||
EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and Atlas TextAsset", "OK");
|
EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and AtlasAsset array", "OK");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("Assets/Spine/Spawn")]
|
[MenuItem("Assets/Spine/Spawn")]
|
||||||
static void SpawnAnimatedSkeleton () {
|
static void SpawnAnimatedSkeleton() {
|
||||||
Object[] arr = Selection.objects;
|
Object[] arr = Selection.objects;
|
||||||
foreach (Object o in arr) {
|
foreach (Object o in arr) {
|
||||||
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o));
|
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o));
|
||||||
@ -474,59 +614,66 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("Assets/Spine/Spawn", true)]
|
[MenuItem("Assets/Spine/Spawn", true)]
|
||||||
static bool ValidateSpawnAnimatedSkeleton () {
|
static bool ValidateSpawnAnimatedSkeleton() {
|
||||||
Object[] arr = Selection.objects;
|
Object[] arr = Selection.objects;
|
||||||
|
|
||||||
if (arr.Length == 0)
|
if (arr.Length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (Object o in arr) {
|
foreach (Object o in arr) {
|
||||||
if (o.GetType() != typeof(SkeletonDataAsset))
|
if (o.GetType() != typeof(SkeletonDataAsset))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SkeletonAnimation SpawnAnimatedSkeleton (SkeletonDataAsset skeletonDataAsset, string skinName) {
|
public static SkeletonAnimation SpawnAnimatedSkeleton(SkeletonDataAsset skeletonDataAsset, string skinName) {
|
||||||
return SpawnAnimatedSkeleton(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName));
|
return SpawnAnimatedSkeleton(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SkeletonAnimation SpawnAnimatedSkeleton (SkeletonDataAsset skeletonDataAsset, Skin skin = null) {
|
public static SkeletonAnimation SpawnAnimatedSkeleton(SkeletonDataAsset skeletonDataAsset, Skin skin = null) {
|
||||||
GameObject go = new GameObject(skeletonDataAsset.name.Replace("_SkeletonData", ""), typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation));
|
GameObject go = new GameObject(skeletonDataAsset.name.Replace("_SkeletonData", ""), typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation));
|
||||||
SkeletonAnimation anim = go.GetComponent<SkeletonAnimation>();
|
SkeletonAnimation anim = go.GetComponent<SkeletonAnimation>();
|
||||||
anim.skeletonDataAsset = skeletonDataAsset;
|
anim.skeletonDataAsset = skeletonDataAsset;
|
||||||
|
|
||||||
bool requiresNormals = false;
|
bool requiresNormals = false;
|
||||||
|
|
||||||
foreach (Material m in anim.skeletonDataAsset.atlasAsset.materials) {
|
foreach (AtlasAsset atlasAsset in anim.skeletonDataAsset.atlasAssets) {
|
||||||
if (m.shader.name.Contains("Lit")) {
|
foreach (Material m in atlasAsset.materials) {
|
||||||
requiresNormals = true;
|
if (m.shader.name.Contains("Lit")) {
|
||||||
break;
|
requiresNormals = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
anim.calculateNormals = requiresNormals;
|
anim.calculateNormals = requiresNormals;
|
||||||
|
|
||||||
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
|
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAsset);
|
for(int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++){
|
||||||
skeletonDataAsset.atlasAsset = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset));
|
string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]);
|
||||||
|
skeletonDataAsset.atlasAssets[i] = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset));
|
||||||
|
}
|
||||||
|
|
||||||
data = skeletonDataAsset.GetSkeletonData(true);
|
data = skeletonDataAsset.GetSkeletonData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skin == null)
|
if (skin == null)
|
||||||
skin = data.DefaultSkin;
|
skin = data.DefaultSkin;
|
||||||
|
|
||||||
if (skin == null)
|
if (skin == null)
|
||||||
skin = data.Skins[0];
|
skin = data.Skins[0];
|
||||||
|
|
||||||
anim.Reset();
|
anim.Reset();
|
||||||
|
|
||||||
anim.skeleton.SetSkin(skin);
|
anim.skeleton.SetSkin(skin);
|
||||||
anim.initialSkinName = skin.Name;
|
anim.initialSkinName = skin.Name;
|
||||||
|
|
||||||
anim.skeleton.Update(1);
|
anim.skeleton.Update(1);
|
||||||
anim.state.Update(1);
|
anim.state.Update(1);
|
||||||
anim.state.Apply(anim.skeleton);
|
anim.state.Apply(anim.skeleton);
|
||||||
@ -534,4 +681,4 @@ public class SpineEditorUtilities : AssetPostprocessor {
|
|||||||
|
|
||||||
return anim;
|
return anim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ using UnityEngine;
|
|||||||
using Spine;
|
using Spine;
|
||||||
|
|
||||||
public class SkeletonDataAsset : ScriptableObject {
|
public class SkeletonDataAsset : ScriptableObject {
|
||||||
public AtlasAsset atlasAsset;
|
public AtlasAsset[] atlasAssets;
|
||||||
public TextAsset skeletonJSON;
|
public TextAsset skeletonJSON;
|
||||||
public float scale = 1;
|
public float scale = 1;
|
||||||
public String[] fromAnimation;
|
public String[] fromAnimation;
|
||||||
@ -45,13 +45,14 @@ public class SkeletonDataAsset : ScriptableObject {
|
|||||||
private SkeletonData skeletonData;
|
private SkeletonData skeletonData;
|
||||||
private AnimationStateData stateData;
|
private AnimationStateData stateData;
|
||||||
|
|
||||||
public void Reset () {
|
public void Reset() {
|
||||||
skeletonData = null;
|
skeletonData = null;
|
||||||
stateData = null;
|
stateData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkeletonData GetSkeletonData (bool quiet) {
|
public SkeletonData GetSkeletonData(bool quiet) {
|
||||||
if (atlasAsset == null) {
|
if (atlasAssets == null) {
|
||||||
|
atlasAssets = new AtlasAsset[0];
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
|
Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
|
||||||
Reset();
|
Reset();
|
||||||
@ -65,16 +66,33 @@ public class SkeletonDataAsset : ScriptableObject {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Atlas atlas = atlasAsset.GetAtlas();
|
|
||||||
if (atlas == null) {
|
|
||||||
|
if (atlasAssets.Length == 0) {
|
||||||
Reset();
|
Reset();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Atlas[] atlasArr = new Atlas[atlasAssets.Length];
|
||||||
|
for (int i = 0; i < atlasAssets.Length; i++) {
|
||||||
|
if (atlasAssets[i] == null) {
|
||||||
|
Reset();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
atlasArr[i] = atlasAssets[i].GetAtlas();
|
||||||
|
if (atlasArr[i] == null) {
|
||||||
|
Reset();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (skeletonData != null)
|
if (skeletonData != null)
|
||||||
return skeletonData;
|
return skeletonData;
|
||||||
|
|
||||||
SkeletonJson json = new SkeletonJson(atlas);
|
SkeletonJson json = new SkeletonJson(atlasArr);
|
||||||
json.Scale = scale;
|
json.Scale = scale;
|
||||||
try {
|
try {
|
||||||
skeletonData = json.ReadSkeletonData(new StringReader(skeletonJSON.text));
|
skeletonData = json.ReadSkeletonData(new StringReader(skeletonJSON.text));
|
||||||
@ -95,7 +113,7 @@ public class SkeletonDataAsset : ScriptableObject {
|
|||||||
return skeletonData;
|
return skeletonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnimationStateData GetAnimationStateData () {
|
public AnimationStateData GetAnimationStateData() {
|
||||||
if (stateData != null)
|
if (stateData != null)
|
||||||
return stateData;
|
return stateData;
|
||||||
GetSkeletonData(false);
|
GetSkeletonData(false);
|
||||||
|
|||||||
@ -38,71 +38,71 @@ using System.Collections;
|
|||||||
using Spine;
|
using Spine;
|
||||||
|
|
||||||
public static class SkeletonExtensions {
|
public static class SkeletonExtensions {
|
||||||
|
|
||||||
public static void SetColor (this Slot slot, Color color) {
|
public static void SetColor(this Slot slot, Color color) {
|
||||||
slot.A = color.a;
|
slot.A = color.a;
|
||||||
slot.R = color.r;
|
slot.R = color.r;
|
||||||
slot.G = color.g;
|
slot.G = color.g;
|
||||||
slot.B = color.b;
|
slot.B = color.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetColor (this Slot slot, Color32 color) {
|
public static void SetColor(this Slot slot, Color32 color) {
|
||||||
slot.A = color.a / 255f;
|
slot.A = color.a / 255f;
|
||||||
slot.R = color.r / 255f;
|
slot.R = color.r / 255f;
|
||||||
slot.G = color.g / 255f;
|
slot.G = color.g / 255f;
|
||||||
slot.B = color.b / 255f;
|
slot.B = color.b / 255f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetColor (this RegionAttachment attachment, Color color) {
|
public static void SetColor(this RegionAttachment attachment, Color color) {
|
||||||
attachment.A = color.a;
|
attachment.A = color.a;
|
||||||
attachment.R = color.r;
|
attachment.R = color.r;
|
||||||
attachment.G = color.g;
|
attachment.G = color.g;
|
||||||
attachment.B = color.b;
|
attachment.B = color.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetColor (this RegionAttachment attachment, Color32 color) {
|
public static void SetColor(this RegionAttachment attachment, Color32 color) {
|
||||||
attachment.A = color.a / 255f;
|
attachment.A = color.a / 255f;
|
||||||
attachment.R = color.r / 255f;
|
attachment.R = color.r / 255f;
|
||||||
attachment.G = color.g / 255f;
|
attachment.G = color.g / 255f;
|
||||||
attachment.B = color.b / 255f;
|
attachment.B = color.b / 255f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetColor (this MeshAttachment attachment, Color color) {
|
public static void SetColor(this MeshAttachment attachment, Color color) {
|
||||||
attachment.A = color.a;
|
attachment.A = color.a;
|
||||||
attachment.R = color.r;
|
attachment.R = color.r;
|
||||||
attachment.G = color.g;
|
attachment.G = color.g;
|
||||||
attachment.B = color.b;
|
attachment.B = color.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetColor (this MeshAttachment attachment, Color32 color) {
|
public static void SetColor(this MeshAttachment attachment, Color32 color) {
|
||||||
attachment.A = color.a / 255f;
|
attachment.A = color.a / 255f;
|
||||||
attachment.R = color.r / 255f;
|
attachment.R = color.r / 255f;
|
||||||
attachment.G = color.g / 255f;
|
attachment.G = color.g / 255f;
|
||||||
attachment.B = color.b / 255f;
|
attachment.B = color.b / 255f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetColor (this SkinnedMeshAttachment attachment, Color color) {
|
public static void SetColor(this SkinnedMeshAttachment attachment, Color color) {
|
||||||
attachment.A = color.a;
|
attachment.A = color.a;
|
||||||
attachment.R = color.r;
|
attachment.R = color.r;
|
||||||
attachment.G = color.g;
|
attachment.G = color.g;
|
||||||
attachment.B = color.b;
|
attachment.B = color.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetColor (this SkinnedMeshAttachment attachment, Color32 color) {
|
public static void SetColor(this SkinnedMeshAttachment attachment, Color32 color) {
|
||||||
attachment.A = color.a / 255f;
|
attachment.A = color.a / 255f;
|
||||||
attachment.R = color.r / 255f;
|
attachment.R = color.r / 255f;
|
||||||
attachment.G = color.g / 255f;
|
attachment.G = color.g / 255f;
|
||||||
attachment.B = color.b / 255f;
|
attachment.B = color.b / 255f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetPosition (this Bone bone, Vector2 position) {
|
public static void SetPosition(this Bone bone, Vector2 position) {
|
||||||
bone.X = position.x;
|
bone.X = position.x;
|
||||||
bone.Y = position.y;
|
bone.Y = position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetPosition (this Bone bone, Vector3 position) {
|
public static void SetPosition(this Bone bone, Vector3 position) {
|
||||||
bone.X = position.x;
|
bone.X = position.x;
|
||||||
bone.Y = position.y;
|
bone.Y = position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -51,6 +51,14 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
public float zSpacing;
|
public float zSpacing;
|
||||||
public bool renderMeshes = true, immutableTriangles;
|
public bool renderMeshes = true, immutableTriangles;
|
||||||
public bool logErrors = false;
|
public bool logErrors = false;
|
||||||
|
|
||||||
|
[SpineSlot]
|
||||||
|
public string[] submeshSeparators = new string[0];
|
||||||
|
|
||||||
|
[HideInInspector]
|
||||||
|
public List<Slot> submeshSeparatorSlots = new List<Slot>();
|
||||||
|
|
||||||
|
|
||||||
private MeshFilter meshFilter;
|
private MeshFilter meshFilter;
|
||||||
private Mesh mesh1, mesh2;
|
private Mesh mesh1, mesh2;
|
||||||
private bool useMesh1;
|
private bool useMesh1;
|
||||||
@ -62,6 +70,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
private Material[] sharedMaterials = new Material[0];
|
private Material[] sharedMaterials = new Material[0];
|
||||||
private readonly List<Material> submeshMaterials = new List<Material>();
|
private readonly List<Material> submeshMaterials = new List<Material>();
|
||||||
private readonly List<Submesh> submeshes = new List<Submesh>();
|
private readonly List<Submesh> submeshes = new List<Submesh>();
|
||||||
|
|
||||||
|
|
||||||
public virtual void Reset () {
|
public virtual void Reset () {
|
||||||
if (meshFilter != null)
|
if (meshFilter != null)
|
||||||
@ -99,6 +108,12 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
skeleton = new Skeleton(skeletonData);
|
skeleton = new Skeleton(skeletonData);
|
||||||
if (initialSkinName != null && initialSkinName.Length > 0 && initialSkinName != "default")
|
if (initialSkinName != null && initialSkinName.Length > 0 && initialSkinName != "default")
|
||||||
skeleton.SetSkin(initialSkinName);
|
skeleton.SetSkin(initialSkinName);
|
||||||
|
|
||||||
|
submeshSeparatorSlots.Clear();
|
||||||
|
for (int i = 0; i < submeshSeparators.Length; i++) {
|
||||||
|
submeshSeparatorSlots.Add(skeleton.FindSlot(submeshSeparators[i]));
|
||||||
|
}
|
||||||
|
|
||||||
if (OnReset != null)
|
if (OnReset != null)
|
||||||
OnReset(this);
|
OnReset(this);
|
||||||
}
|
}
|
||||||
@ -156,7 +171,8 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
|
|
||||||
// Populate submesh when material changes.
|
// Populate submesh when material changes.
|
||||||
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
||||||
if ((lastMaterial != material && lastMaterial != null) || slot.Data.name[0] == '*') {
|
|
||||||
|
if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot)) {
|
||||||
AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
|
AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
|
||||||
submeshTriangleCount = 0;
|
submeshTriangleCount = 0;
|
||||||
submeshFirstVertex = vertexCount;
|
submeshFirstVertex = vertexCount;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
public class SkeletonUtilityKinematicShadow : MonoBehaviour {
|
public class SkeletonUtilityKinematicShadow : MonoBehaviour {
|
||||||
public bool hideShadow = true;
|
public bool hideShadow = true;
|
||||||
|
public Transform parent;
|
||||||
Dictionary<Transform, Transform> shadowTable;
|
Dictionary<Transform, Transform> shadowTable;
|
||||||
GameObject shadowRoot;
|
GameObject shadowRoot;
|
||||||
|
|
||||||
@ -12,7 +13,10 @@ public class SkeletonUtilityKinematicShadow : MonoBehaviour {
|
|||||||
if (hideShadow)
|
if (hideShadow)
|
||||||
shadowRoot.hideFlags = HideFlags.HideInHierarchy;
|
shadowRoot.hideFlags = HideFlags.HideInHierarchy;
|
||||||
|
|
||||||
shadowRoot.transform.parent = transform.root;
|
if(parent == null)
|
||||||
|
shadowRoot.transform.parent = transform.root;
|
||||||
|
else
|
||||||
|
shadowRoot.transform.parent = parent;
|
||||||
|
|
||||||
shadowTable = new Dictionary<Transform, Transform>();
|
shadowTable = new Dictionary<Transform, Transform>();
|
||||||
|
|
||||||
|
|||||||
111
spine-unity/Assets/spine-unity/SpineAttributes.cs
Normal file
111
spine-unity/Assets/spine-unity/SpineAttributes.cs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
public class SpineSlot : PropertyAttribute {
|
||||||
|
public string startsWith = "";
|
||||||
|
public string dataSource = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startsWith"></param>
|
||||||
|
/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
|
||||||
|
public SpineSlot(string startsWith = "", string dataSource = "") {
|
||||||
|
this.startsWith = startsWith;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpineSkin : PropertyAttribute {
|
||||||
|
public string startsWith = "";
|
||||||
|
public string dataSource = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startsWith"></param>
|
||||||
|
/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
|
||||||
|
public SpineSkin(string startsWith = "", string dataSource = "") {
|
||||||
|
this.startsWith = startsWith;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpineAtlasRegion : PropertyAttribute {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpineAnimation : PropertyAttribute {
|
||||||
|
public string startsWith = "";
|
||||||
|
public string dataSource = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startsWith"></param>
|
||||||
|
/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
|
||||||
|
public SpineAnimation(string startsWith = "", string dataSource = "") {
|
||||||
|
this.startsWith = startsWith;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpineAttachment : PropertyAttribute {
|
||||||
|
public bool returnFullPath;
|
||||||
|
public bool currentSkinOnly;
|
||||||
|
public string dataSource = "";
|
||||||
|
public string slotSource = "";
|
||||||
|
|
||||||
|
|
||||||
|
public SpineAttachment() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpineAttachment(bool currentSkinOnly = true, bool returnFullPath = false, string slot = "", string dataSource = "") {
|
||||||
|
this.currentSkinOnly = currentSkinOnly;
|
||||||
|
this.returnFullPath = returnFullPath;
|
||||||
|
this.slotSource = slot;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Hierarchy GetHierarchy(string fullPath) {
|
||||||
|
return new Hierarchy(fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Spine.Attachment GetAttachment(string fullPath, Spine.SkeletonData skeletonData) {
|
||||||
|
var hierarchy = SpineAttachment.GetHierarchy(fullPath);
|
||||||
|
if (hierarchy.name == "")
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Spine.Attachment GetAttachment(string fullPath, SkeletonDataAsset skeletonDataAsset) {
|
||||||
|
return GetAttachment(fullPath, skeletonDataAsset.GetSkeletonData(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Hierarchy {
|
||||||
|
public string skin;
|
||||||
|
public string slot;
|
||||||
|
public string name;
|
||||||
|
|
||||||
|
public Hierarchy(string fullPath) {
|
||||||
|
string[] chunks = fullPath.Split(new char[]{'/'}, System.StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (chunks.Length == 0) {
|
||||||
|
skin = "";
|
||||||
|
slot = "";
|
||||||
|
name = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (chunks.Length < 2) {
|
||||||
|
throw new System.Exception("Cannot generate Attachment Hierarchy from string! Not enough components! [" + fullPath + "]");
|
||||||
|
}
|
||||||
|
skin = chunks[0];
|
||||||
|
slot = chunks[1];
|
||||||
|
name = "";
|
||||||
|
for (int i = 2; i < chunks.Length; i++) {
|
||||||
|
name += chunks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
spine-unity/Assets/spine-unity/SpineAttributes.cs.meta
Normal file
8
spine-unity/Assets/spine-unity/SpineAttributes.cs.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ce216f51ebc1d3f40929f4e58d1c65e5
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
Loading…
x
Reference in New Issue
Block a user