diff --git a/spine-unity/Assets/spine-unity/BoneComponent.cs b/spine-unity/Assets/spine-unity/BoneFollower.cs similarity index 85% rename from spine-unity/Assets/spine-unity/BoneComponent.cs rename to spine-unity/Assets/spine-unity/BoneFollower.cs index acfe183cb..5c8fa3f92 100644 --- a/spine-unity/Assets/spine-unity/BoneComponent.cs +++ b/spine-unity/Assets/spine-unity/BoneFollower.cs @@ -36,8 +36,9 @@ using Spine; /// Sets a GameObject's transform to match a bone on a Spine skeleton. [ExecuteInEditMode] -[AddComponentMenu("Spine/BoneComponent")] -public class BoneComponent : MonoBehaviour { +[AddComponentMenu("Spine/BoneFollower")] +public class BoneFollower : MonoBehaviour { + [System.NonSerialized] public bool valid; @@ -55,31 +56,50 @@ public class BoneComponent : MonoBehaviour { } } - // TODO: Make the rotation behavior more customizable - // public bool followTransformRotation = false; - - // TODO: Make transform follow bone scale? too specific? This is really useful for shared shadow assets. - //public bool followBoneScale = false; /// If a bone isn't set, boneName is used to find the bone. public String boneName; + public bool resetOnAwake = true; + protected Transform cachedTransform; protected Transform skeletonTransform; - + + public void HandleResetRenderer(SkeletonRenderer skeletonRenderer){ + Reset(); + } + public void Reset () { bone = null; cachedTransform = transform; valid = skeletonRenderer != null && skeletonRenderer.valid; if (!valid) return; skeletonTransform = skeletonRenderer.transform; + + skeletonRenderer.OnReset -= HandleResetRenderer; + skeletonRenderer.OnReset += HandleResetRenderer; + + if(Application.isEditor) + DoUpdate(); + } + + void OnDestroy(){ + //cleanup + if(skeletonRenderer != null) + skeletonRenderer.OnReset -= HandleResetRenderer; } public void Awake () { - Reset(); + if(resetOnAwake) + Reset(); } - public void LateUpdate () { + void LateUpdate(){ + DoUpdate(); + } + + + public void DoUpdate () { if (!valid) { Reset(); return; @@ -92,6 +112,9 @@ public class BoneComponent : MonoBehaviour { Debug.LogError("Bone not found: " + boneName, this); return; } + else{ + + } } Spine.Skeleton skeleton = skeletonRenderer.skeleton; @@ -113,9 +136,10 @@ public class BoneComponent : MonoBehaviour { if(followBoneRotation) { Vector3 rotation = skeletonTransform.rotation.eulerAngles; - cachedTransform.rotation = Quaternion.Euler(rotation.x, rotation.y, - skeletonTransform.rotation.eulerAngles.z + (bone.worldRotation * flipRotation) ); + + cachedTransform.rotation = Quaternion.Euler(rotation.x, rotation.y, skeletonTransform.rotation.eulerAngles.z + (bone.worldRotation * flipRotation) ); } } + } } \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/BoneComponent.cs.meta b/spine-unity/Assets/spine-unity/BoneFollower.cs.meta similarity index 78% rename from spine-unity/Assets/spine-unity/BoneComponent.cs.meta rename to spine-unity/Assets/spine-unity/BoneFollower.cs.meta index a6a16dd66..29dabc13e 100644 --- a/spine-unity/Assets/spine-unity/BoneComponent.cs.meta +++ b/spine-unity/Assets/spine-unity/BoneFollower.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 487b42efe96d8cc408a757541ea3f169 +guid: a1fd8daaed7b64148a34acb96ba14ce1 MonoImporter: serializedVersion: 2 defaultReferences: [] diff --git a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs new file mode 100644 index 000000000..bbf164b4e --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs @@ -0,0 +1,106 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof(BoneFollower))] +public class BoneFollowerInspector : Editor { + private SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation; + BoneFollower component; + void OnEnable () { + skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); + boneName = serializedObject.FindProperty("boneName"); + followBoneRotation = serializedObject.FindProperty("followBoneRotation"); + followZPosition = serializedObject.FindProperty("followZPosition"); + component = (BoneFollower)target; + ForceReload(); + } + + void FindRenderer(){ + if(skeletonRenderer.objectReferenceValue == null){ + SkeletonRenderer parentRenderer = component.GetComponentInParent(); + if(parentRenderer != null){ + skeletonRenderer.objectReferenceValue = (UnityEngine.Object)parentRenderer; + } + } + } + + void ForceReload(){ + if(component.skeletonRenderer != null){ + if(component.skeletonRenderer.valid == false) + component.skeletonRenderer.Reset(); + } + } + + override public void OnInspectorGUI () { + serializedObject.Update(); + + FindRenderer(); + + EditorGUILayout.PropertyField(skeletonRenderer); + + if (component.valid) { + String[] bones = new String[1]; + try{ + bones = new String[component.skeletonRenderer.skeleton.Data.Bones.Count + 1]; + } + catch{ + + } + + bones[0] = ""; + for (int i = 0; i < bones.Length - 1; i++) + bones[i + 1] = component.skeletonRenderer.skeleton.Data.Bones[i].Name; + Array.Sort(bones); + int boneIndex = Math.Max(0, Array.IndexOf(bones, boneName.stringValue)); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Bone"); + EditorGUIUtility.LookLikeControls(); + boneIndex = EditorGUILayout.Popup(boneIndex, bones); + EditorGUILayout.EndHorizontal(); + + boneName.stringValue = boneIndex == 0 ? null : bones[boneIndex]; + EditorGUILayout.PropertyField(followBoneRotation); + EditorGUILayout.PropertyField(followZPosition); + } + else{ + GUILayout.Label("INVALID"); + } + + if (serializedObject.ApplyModifiedProperties() || + (Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed") + ) { + component.Reset(); + } + } +} diff --git a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs.meta new file mode 100644 index 000000000..a5cf9ae89 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c71ca35fd6241cb49a0b0756a664fcf7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-animation.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-animation.png.meta index f8ac9f868..6d9bc41dd 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-animation.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-animation.png.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 guid: 52b12ec801461494185a4d3dc66f3d1d TextureImporter: + fileIDToRecycleName: {} serializedVersion: 2 mipmaps: mipMapMode: 0 diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-animationRoot.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-animationRoot.png.meta index 1b4c1e24f..4bcf433e8 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-animationRoot.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-animationRoot.png.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 guid: 3d1be4ea889f3a14b864352fe49a1bde TextureImporter: + fileIDToRecycleName: {} serializedVersion: 2 mipmaps: mipMapMode: 0 diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-bone.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-bone.png new file mode 100644 index 000000000..ec66a6a85 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-bone.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-bone.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-bone.png.meta new file mode 100644 index 000000000..9c59ed87d --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-bone.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8322793223a533a4ca8be6f430256dfc +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-boneNib.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boneNib.png new file mode 100644 index 000000000..87373b8f0 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boneNib.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-boneNib.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boneNib.png.meta new file mode 100644 index 000000000..955598a84 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boneNib.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 97a43f11e00735147a9dc3dff6d68191 +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png new file mode 100644 index 000000000..82beedfce Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png.meta new file mode 100644 index 000000000..c90f54d3c --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 955aed20030d0504b8a9c6934a5cb47a +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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-constraintNib.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-constraintNib.png new file mode 100644 index 000000000..175bcb047 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-constraintNib.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-constraintNib.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-constraintNib.png.meta new file mode 100644 index 000000000..e7ab7aca3 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-constraintNib.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: de1a4f5ad4bdf1a4ea072c4d59ba87d8 +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-event.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-event.png.meta index 71c672b9c..2ab786189 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-event.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-event.png.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 guid: d226a80acc775714aa78b85e16a00e9b TextureImporter: + fileIDToRecycleName: {} serializedVersion: 2 mipmaps: mipMapMode: 0 diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png new file mode 100644 index 000000000..a27af1c7c Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png.meta new file mode 100644 index 000000000..6f346e072 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 2c2c6d283dcf3654baf40001c982891c +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: -1 + maxTextureSize: 1024 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-image.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-image.png new file mode 100644 index 000000000..663d11350 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-image.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-image.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-image.png.meta new file mode 100644 index 000000000..24d78a242 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-image.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 2b3a6f35bbaa8414eb51a344743ee641 +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-mesh.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-mesh.png new file mode 100644 index 000000000..1035553b7 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-mesh.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-mesh.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-mesh.png.meta new file mode 100644 index 000000000..a98b0e9c8 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-mesh.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: a309a2e14638a204091b915126910f45 +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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-null.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-null.png new file mode 100644 index 000000000..9a6d738eb Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-null.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-null.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-null.png.meta new file mode 100644 index 000000000..a949f63a6 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-null.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d1de1604dfe4cb64c9d31246a8e43c78 +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-poseBones.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-poseBones.png new file mode 100644 index 000000000..102700af0 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-poseBones.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-poseBones.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-poseBones.png.meta new file mode 100644 index 000000000..c3748ea88 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-poseBones.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: da6f6d414e43aac46a57cc5a87208db4 +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeleton.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeleton.png.meta index 2b8ef8c4f..f607575fb 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeleton.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeleton.png.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 guid: f2216037084d99d4481810cb521ed96f TextureImporter: + fileIDToRecycleName: {} serializedVersion: 2 mipmaps: mipMapMode: 0 diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeletonUtility.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeletonUtility.png new file mode 100644 index 000000000..ce4d937b2 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeletonUtility.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeletonUtility.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeletonUtility.png.meta new file mode 100644 index 000000000..9d3c22794 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skeletonUtility.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 5bb0631368b462047869d8788673cb48 +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skin.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skin.png new file mode 100644 index 000000000..3d9bddeb4 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skin.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skin.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skin.png.meta new file mode 100644 index 000000000..3be7a6e69 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skin.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: bfd9f3d2607e9e44c97384d7575a17dc +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinPlaceholder.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinPlaceholder.png new file mode 100644 index 000000000..3b11d379e Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinPlaceholder.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinPlaceholder.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinPlaceholder.png.meta new file mode 100644 index 000000000..e6ebc95cc --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinPlaceholder.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 04c82a4acf7b5244e947f2709ec3a6cf +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinsRoot.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinsRoot.png.meta index ab536e515..e332380e8 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinsRoot.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-skinsRoot.png.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 guid: 8bd14c7643597a74ba2edc10a5e4c4ed TextureImporter: + fileIDToRecycleName: {} serializedVersion: 2 mipmaps: mipMapMode: 0 diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-slot.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-slot.png new file mode 100644 index 000000000..ca938722d Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-slot.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-slot.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-slot.png.meta new file mode 100644 index 000000000..89224b580 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-slot.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 0338faf3e7d93e2478fcbc022d13e081 +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-spine.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-spine.png.meta index e620c9210..c0ec65ca2 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-spine.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-spine.png.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 guid: 4e7c964fa5e07024c8bf1debecc3b7c8 TextureImporter: + fileIDToRecycleName: {} serializedVersion: 2 mipmaps: mipMapMode: 0 diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png new file mode 100644 index 000000000..ec7c9e64b Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta new file mode 100644 index 000000000..35500c50d --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f31c0c0d608e8ba4f9a1afb032092287 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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: -1 + maxTextureSize: 1024 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-warning.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-warning.png new file mode 100644 index 000000000..05e3f4cdc Binary files /dev/null and b/spine-unity/Assets/spine-unity/Editor/GUI/icon-warning.png differ diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-warning.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-warning.png.meta new file mode 100644 index 000000000..e32950ca4 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-warning.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 754d724c1bd750048852e8cf3d4a05ee +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: -3 + 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: diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs index bc6d6b19c..f8d29894e 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs @@ -31,16 +31,23 @@ using System; using UnityEditor; using UnityEngine; +using Spine; [CustomEditor(typeof(SkeletonAnimation))] public class SkeletonAnimationInspector : SkeletonRendererInspector { protected SerializedProperty animationName, loop, timeScale; + protected bool isPrefab; protected override void OnEnable () { base.OnEnable(); animationName = serializedObject.FindProperty("_animationName"); loop = serializedObject.FindProperty("loop"); timeScale = serializedObject.FindProperty("timeScale"); + + if(PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab) + isPrefab = true; + + } protected override void gui () { @@ -49,6 +56,25 @@ public class SkeletonAnimationInspector : SkeletonRendererInspector { SkeletonAnimation component = (SkeletonAnimation)target; if (!component.valid) return; + //catch case where SetAnimation was used to set track 0 without using AnimationName + if(Application.isPlaying){ + TrackEntry currentState = component.state.GetCurrent(0); + if(currentState != null){ + if(component.AnimationName != animationName.stringValue){ + animationName.stringValue = currentState.Animation.Name; + } + + if(loop.boolValue != currentState.Loop){ + loop.boolValue = currentState.Loop; + } + + if(timeScale.floatValue != currentState.TimeScale){ + timeScale.floatValue = currentState.TimeScale; + } + } + } + + // Animation name. { String[] animations = new String[component.skeleton.Data.Animations.Count + 1]; @@ -69,10 +95,21 @@ public class SkeletonAnimationInspector : SkeletonRendererInspector { String selectedAnimationName = animationIndex == 0 ? null : animations[animationIndex]; component.AnimationName = selectedAnimationName; animationName.stringValue = selectedAnimationName; + + } EditorGUILayout.PropertyField(loop); EditorGUILayout.PropertyField(timeScale); component.timeScale = Math.Max(component.timeScale, 0); + EditorGUILayout.Space(); + + if(!isPrefab){ + if(component.GetComponent() == null){ + if(GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))){ + component.gameObject.AddComponent(); + } + } + } } } diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs index d77647e42..09618fa45 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs @@ -28,6 +28,11 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +/***************************************************************************** + * Automatic import and advanced preview added by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ + using System; using System.Collections.Generic; using UnityEditor; @@ -53,18 +58,26 @@ public class SkeletonDataAssetInspector : Editor { private string m_skeletonDataAssetGUID; void OnEnable () { - atlasAsset = serializedObject.FindProperty("atlasAsset"); - skeletonJSON = serializedObject.FindProperty("skeletonJSON"); - scale = serializedObject.FindProperty("scale"); - fromAnimation = serializedObject.FindProperty("fromAnimation"); - toAnimation = serializedObject.FindProperty("toAnimation"); - duration = serializedObject.FindProperty("duration"); - defaultMix = serializedObject.FindProperty("defaultMix"); - - m_skeletonDataAsset = (SkeletonDataAsset)target; - m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath(m_skeletonDataAsset) ); - - EditorApplication.update += Update; + try{ + + atlasAsset = serializedObject.FindProperty("atlasAsset"); + skeletonJSON = serializedObject.FindProperty("skeletonJSON"); + scale = serializedObject.FindProperty("scale"); + fromAnimation = serializedObject.FindProperty("fromAnimation"); + toAnimation = serializedObject.FindProperty("toAnimation"); + duration = serializedObject.FindProperty("duration"); + defaultMix = serializedObject.FindProperty("defaultMix"); + + m_skeletonDataAsset = (SkeletonDataAsset)target; + m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath(m_skeletonDataAsset) ); + + EditorApplication.update += Update; + + } + catch{ + + + } } void OnDestroy(){ diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index eec7fc04d..ef614a1e0 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -1,4 +1,38 @@ #pragma warning disable 0219 +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Spine Editor Utilities created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ using UnityEngine; using UnityEditor; @@ -15,6 +49,7 @@ public class SpineEditorUtilities : AssetPostprocessor { public static Texture2D skeleton; public static Texture2D nullBone; public static Texture2D bone; + public static Texture2D poseBones; public static Texture2D boneNib; public static Texture2D slot; public static Texture2D skinPlaceholder; @@ -27,6 +62,11 @@ public class SpineEditorUtilities : AssetPostprocessor { public static Texture2D animationRoot; public static Texture2D spine; public static Texture2D _event; + public static Texture2D constraintNib; + public static Texture2D warning; + public static Texture2D skeletonUtility; + public static Texture2D hingeChain; + public static Texture2D subMeshRenderer; public static Mesh boneMesh{ get{ @@ -61,6 +101,7 @@ public class SpineEditorUtilities : AssetPostprocessor { skeleton = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-skeleton.png"); nullBone = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-null.png"); bone = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-bone.png"); + poseBones = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-poseBones.png"); boneNib = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-boneNib.png"); slot = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-slot.png"); skinPlaceholder = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png"); @@ -73,6 +114,12 @@ public class SpineEditorUtilities : AssetPostprocessor { animationRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-animationRoot.png"); spine = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-spine.png"); _event = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-event.png"); + constraintNib = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-constraintNib.png"); + warning = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-warning.png"); + skeletonUtility = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-skeletonUtility.png"); + hingeChain = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-hingeChain.png"); + subMeshRenderer = (Texture2D)AssetDatabase.LoadMainAssetAtPath( SpineEditorUtilities.editorGUIPath + "/icon-subMeshRenderer.png"); + } } @@ -81,8 +128,9 @@ public class SpineEditorUtilities : AssetPostprocessor { public static string editorPath = ""; public static string editorGUIPath = ""; - - static List skeletonRendererInstanceIDs; + + static Dictionary skeletonRendererTable; + static Dictionary skeletonUtilityBoneTable; public static float defaultScale = 0.01f; public static float defaultMix = 0.2f; @@ -96,7 +144,8 @@ public class SpineEditorUtilities : AssetPostprocessor { Icons.Initialize(); - skeletonRendererInstanceIDs = new List(); + skeletonRendererTable = new Dictionary(); + skeletonUtilityBoneTable = new Dictionary(); EditorApplication.hierarchyWindowChanged += HierarchyWindowChanged; EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI; @@ -105,22 +154,49 @@ public class SpineEditorUtilities : AssetPostprocessor { } static void HierarchyWindowChanged(){ - skeletonRendererInstanceIDs.Clear(); + skeletonRendererTable.Clear(); + skeletonUtilityBoneTable.Clear(); SkeletonRenderer[] arr = Object.FindObjectsOfType(); foreach(SkeletonRenderer r in arr) - skeletonRendererInstanceIDs.Add(r.gameObject.GetInstanceID()); + skeletonRendererTable.Add( r.gameObject.GetInstanceID(), r.gameObject ); + + SkeletonUtilityBone[] boneArr = Object.FindObjectsOfType(); + foreach(SkeletonUtilityBone b in boneArr) + skeletonUtilityBoneTable.Add(b.gameObject.GetInstanceID(), b); } static void HierarchyWindowItemOnGUI(int instanceId, Rect selectionRect){ - if(skeletonRendererInstanceIDs.Contains(instanceId)){ + if(skeletonRendererTable.ContainsKey(instanceId)){ Rect r = new Rect (selectionRect); r.x = r.width - 15; r.width = 15; GUI.Label(r, Icons.spine); } + else if(skeletonUtilityBoneTable.ContainsKey(instanceId)){ + Rect r = new Rect (selectionRect); + //r.x = r.width - 15; + r.x -= 26; + + if(skeletonUtilityBoneTable[instanceId] != null){ + if( skeletonUtilityBoneTable[instanceId].transform.childCount == 0 ) + r.x += 15; + + + r.width = 15; + + if( skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow ){ + GUI.Label(r, Icons.bone); + } + else{ + GUI.Label(r, Icons.poseBones); + } + } + + } + } [MenuItem("Assets/Spine/Ingest")] @@ -335,20 +411,24 @@ public class SpineEditorUtilities : AssetPostprocessor { string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); string assetPath = Path.GetDirectoryName( AssetDatabase.GetAssetPath(spineJson)); + string filePath = assetPath + "/" + primaryName + "_SkeletonData.asset"; if(spineJson != null && atlasAsset != null){ - SkeletonDataAsset skelDataAsset = SkeletonDataAsset.CreateInstance(); - skelDataAsset.atlasAsset = atlasAsset; - skelDataAsset.skeletonJSON = spineJson; - skelDataAsset.fromAnimation = new string[0]; - skelDataAsset.toAnimation = new string[0]; - skelDataAsset.duration = new float[0]; - skelDataAsset.defaultMix = defaultMix; - skelDataAsset.scale = defaultScale; - - AssetDatabase.CreateAsset(skelDataAsset, assetPath + "/" + primaryName + "_SkeletonData.asset"); - AssetDatabase.SaveAssets(); + SkeletonDataAsset skelDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset)); + if(skelDataAsset == null){ + skelDataAsset = SkeletonDataAsset.CreateInstance(); + skelDataAsset.atlasAsset = atlasAsset; + skelDataAsset.skeletonJSON = spineJson; + skelDataAsset.fromAnimation = new string[0]; + skelDataAsset.toAnimation = new string[0]; + skelDataAsset.duration = new float[0]; + skelDataAsset.defaultMix = defaultMix; + skelDataAsset.scale = defaultScale; + + AssetDatabase.CreateAsset(skelDataAsset, filePath); + AssetDatabase.SaveAssets(); + } return skelDataAsset; } diff --git a/spine-unity/Assets/spine-unity/Shaders/Bones.shader b/spine-unity/Assets/spine-unity/Shaders/Bones.shader new file mode 100644 index 000000000..61fc977e5 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Shaders/Bones.shader @@ -0,0 +1,69 @@ +Shader "Spine/Bones" { +Properties { + _Color ("Color", Color) = (0.5,0.5,0.5,0.5) + _MainTex ("Particle Texture", 2D) = "white" {} +} + +Category { + Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } + Blend SrcAlpha OneMinusSrcAlpha + AlphaTest Greater .01 + ColorMask RGB + + Lighting Off Cull Off ZTest Always ZWrite Off Fog { Mode Off } + + SubShader { + Pass { + + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma multi_compile_particles + + #include "UnityCG.cginc" + + sampler2D _MainTex; + fixed4 _Color; + + struct appdata_t { + float4 vertex : POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; + + struct v2f { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + #ifdef SOFTPARTICLES_ON + float4 projPos : TEXCOORD1; + #endif + }; + + float4 _MainTex_ST; + + v2f vert (appdata_t v) + { + v2f o; + o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); + #ifdef SOFTPARTICLES_ON + o.projPos = ComputeScreenPos (o.vertex); + COMPUTE_EYEDEPTH(o.projPos.z); + #endif + o.color = v.color; + o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); + return o; + } + + sampler2D_float _CameraDepthTexture; + + + fixed4 frag (v2f i) : SV_Target + { + return 2.0f * i.color * _Color * tex2D(_MainTex, i.texcoord); + } + ENDCG + } + } +} +} diff --git a/spine-unity/Assets/spine-unity/Shaders/Bones.shader.meta b/spine-unity/Assets/spine-unity/Shaders/Bones.shader.meta new file mode 100644 index 000000000..d01814ef9 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Shaders/Bones.shader.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 66988de88a15abd4e8846c6805485f57 +ShaderImporter: + defaultTextures: [] + userData: diff --git a/spine-unity/Assets/spine-unity/Shaders/HiddenPass.mat b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.mat new file mode 100644 index 000000000..31cf39d99 Binary files /dev/null and b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.mat differ diff --git a/spine-unity/Assets/spine-unity/Shaders/HiddenPass.mat.meta b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.mat.meta new file mode 100644 index 000000000..ef267ef07 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 43227e5adadc6f24bb4bf74b92a56fb4 +NativeFormatImporter: + userData: diff --git a/spine-unity/Assets/spine-unity/Shaders/HiddenPass.shader b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.shader new file mode 100644 index 000000000..3a0de6756 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.shader @@ -0,0 +1,21 @@ +Shader "Spine/HiddenPass" { + SubShader + + { + + Tags {"Queue" = "Geometry-1" } + + Lighting Off + + Pass + + { + + ZWrite Off + + ColorMask 0 + + } + + } +} diff --git a/spine-unity/Assets/spine-unity/Shaders/HiddenPass.shader.meta b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.shader.meta new file mode 100644 index 000000000..bcc031d30 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Shaders/HiddenPass.shader.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 913475501bf19374c84390868a9d6d3d +ShaderImporter: + defaultTextures: [] + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonAnimation.cs b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs index 8810a5383..b2b367167 100644 --- a/spine-unity/Assets/spine-unity/SkeletonAnimation.cs +++ b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs @@ -42,7 +42,9 @@ public class SkeletonAnimation : SkeletonRenderer { public Spine.AnimationState state; public delegate void UpdateBonesDelegate(SkeletonAnimation skeleton); - public UpdateBonesDelegate UpdateBones; + public UpdateBonesDelegate UpdateLocal; + public UpdateBonesDelegate UpdateWorld; + public UpdateBonesDelegate UpdateComplete; [SerializeField] private String _animationName; @@ -83,7 +85,19 @@ public class SkeletonAnimation : SkeletonRenderer { skeleton.Update(deltaTime); state.Update(deltaTime); state.Apply(skeleton); - if (UpdateBones != null) UpdateBones(this); + + if (UpdateLocal != null) + UpdateLocal(this); + skeleton.UpdateWorldTransform(); + + if (UpdateWorld != null){ + UpdateWorld(this); + skeleton.UpdateWorldTransform(); + } + + if (UpdateComplete != null){ + UpdateComplete(this); + } } } diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index ca8e263df..06b414658 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs @@ -1,4 +1,39 @@ -using UnityEngine; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Spine Extensions created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ + +using UnityEngine; using System.Collections; using Spine; diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 56d475131..a09838247 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -37,6 +37,10 @@ using Spine; /// Renders a skeleton. [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] public class SkeletonRenderer : MonoBehaviour { + + public delegate void SkeletonRendererDelegate(SkeletonRenderer skeletonRenderer); + public SkeletonRendererDelegate OnReset; + [System.NonSerialized] public bool valid; [System.NonSerialized] @@ -96,6 +100,7 @@ public class SkeletonRenderer : MonoBehaviour { skeleton = new Skeleton(skeletonData); if (initialSkinName != null && initialSkinName.Length > 0 && initialSkinName != "default") skeleton.SetSkin(initialSkinName); + if(OnReset != null) OnReset(this); } public void Awake () { @@ -112,7 +117,6 @@ public class SkeletonRenderer : MonoBehaviour { public virtual void LateUpdate () { if (!valid) return; - // Count vertices and submesh triangles. int vertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; @@ -122,7 +126,8 @@ public class SkeletonRenderer : MonoBehaviour { int drawOrderCount = drawOrder.Count; bool renderMeshes = this.renderMeshes; for (int i = 0; i < drawOrderCount; i++) { - Attachment attachment = drawOrder[i].attachment; + Slot slot = drawOrder[i]; + Attachment attachment = slot.attachment; object rendererObject; int attachmentVertexCount, attachmentTriangleCount; @@ -149,7 +154,7 @@ public class SkeletonRenderer : MonoBehaviour { // Populate submesh when material changes. Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; - if (lastMaterial != material && lastMaterial != null) { + if ((lastMaterial != material && lastMaterial != null) || slot.Data.name[0] == '*') { AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false); submeshTriangleCount = 0; submeshFirstVertex = vertexCount; diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility.meta b/spine-unity/Assets/spine-unity/SkeletonUtility.meta new file mode 100644 index 000000000..d690c94de --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f6e0caaafe294de48af468a6a9321473 +folderAsset: yes +DefaultImporter: + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor.meta new file mode 100644 index 000000000..386e1e90b --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: a751a9d1e3e26d64d997b66a781df8e9 +folderAsset: yes +DefaultImporter: + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs new file mode 100644 index 000000000..1a6b80054 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs @@ -0,0 +1,287 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Skeleton Utility created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ + +using UnityEngine; +using UnityEditor; +using System.Collections; +using System.Collections.Generic; +using Spine; + +[CustomEditor(typeof(SkeletonUtilityBone)), CanEditMultipleObjects] +public class SkeletonUtilityBoneInspector : Editor { + SerializedProperty mode, boneName, zPosition, position, rotation, scale, overrideAlpha, parentReference; + + //multi selected flags + bool containsFollows, containsOverrides, multiObject; + + //single selected helpers + SkeletonUtilityBone utilityBone; + SkeletonUtility skeletonUtility; + bool canCreateHingeChain = false; + + void OnEnable(){ + mode = this.serializedObject.FindProperty("mode"); + boneName = this.serializedObject.FindProperty("boneName"); + zPosition = this.serializedObject.FindProperty("zPosition"); + position = this.serializedObject.FindProperty("position"); + rotation = this.serializedObject.FindProperty("rotation"); + scale = this.serializedObject.FindProperty("scale"); + overrideAlpha = this.serializedObject.FindProperty("overrideAlpha"); + parentReference = this.serializedObject.FindProperty("parentReference"); + + EvaluateFlags(); + + if(utilityBone.valid == false && skeletonUtility != null && skeletonUtility.skeletonRenderer != null){ + skeletonUtility.skeletonRenderer.Reset(); + } + + canCreateHingeChain = CanCreateHingeChain(); + } + + /// + /// Evaluates the flags. + /// + void EvaluateFlags(){ + utilityBone = (SkeletonUtilityBone)target; + skeletonUtility = utilityBone.skeletonUtility; + + if(Selection.objects.Length == 1){ + containsFollows = utilityBone.mode == SkeletonUtilityBone.Mode.Follow; + containsOverrides = utilityBone.mode == SkeletonUtilityBone.Mode.Override; + } + else{ + int boneCount = 0; + foreach(Object o in Selection.objects){ + if(o is GameObject){ + GameObject go = (GameObject)o; + SkeletonUtilityBone sub = go.GetComponent(); + if(sub != null){ + boneCount++; + if(sub.mode == SkeletonUtilityBone.Mode.Follow) + containsFollows = true; + if(sub.mode == SkeletonUtilityBone.Mode.Override) + containsOverrides = true; + } + } + } + + if(boneCount > 1) + multiObject = true; + } + } + + public override void OnInspectorGUI () + { + serializedObject.Update(); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(mode); + if(EditorGUI.EndChangeCheck()){ + containsOverrides = mode.enumValueIndex == 1; + containsFollows = mode.enumValueIndex == 0; + } + + EditorGUI.BeginDisabledGroup( multiObject ); + { + string str = boneName.stringValue; + if(str == "") str = ""; + if(multiObject) str = ""; + + GUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Bone"); + + if(GUILayout.Button( str, EditorStyles.popup )){ + BoneSelectorContextMenu( str, ((SkeletonUtilityBone)target).skeletonUtility.skeletonRenderer.skeleton.Bones, "", TargetBoneSelected ); + } + + GUILayout.EndHorizontal(); + } + EditorGUI.EndDisabledGroup(); + + EditorGUILayout.PropertyField(zPosition); + EditorGUILayout.PropertyField(position); + EditorGUILayout.PropertyField(rotation); + EditorGUILayout.PropertyField(scale); + + EditorGUI.BeginDisabledGroup( containsFollows ); + { + EditorGUILayout.PropertyField(overrideAlpha); + EditorGUILayout.PropertyField(parentReference); + } + EditorGUI.EndDisabledGroup(); + + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + { + EditorGUI.BeginDisabledGroup( multiObject || !utilityBone.valid || utilityBone.bone == null || utilityBone.bone.Children.Count == 0); + { + if(GUILayout.Button(new GUIContent("Add Child", SpineEditorUtilities.Icons.bone), GUILayout.Width(150), GUILayout.Height(24))) + BoneSelectorContextMenu( "", utilityBone.bone.Children, "", SpawnChildBoneSelected); + } + EditorGUI.EndDisabledGroup(); + + EditorGUI.BeginDisabledGroup( multiObject || !utilityBone.valid || utilityBone.bone == null || containsOverrides); + { + if(GUILayout.Button(new GUIContent("Add Override", SpineEditorUtilities.Icons.poseBones), GUILayout.Width(150), GUILayout.Height(24))) + SpawnOverride(); + } + EditorGUI.EndDisabledGroup(); + + EditorGUI.BeginDisabledGroup( multiObject || !utilityBone.valid || !canCreateHingeChain ); + { + if(GUILayout.Button(new GUIContent("Create Hinge Chain", SpineEditorUtilities.Icons.hingeChain), GUILayout.Width(150), GUILayout.Height(24))) + CreateHingeChain(); + } + EditorGUI.EndDisabledGroup(); + + } + GUILayout.EndHorizontal(); + + serializedObject.ApplyModifiedProperties(); + } + + void BoneSelectorContextMenu(string current, List bones, string topValue, GenericMenu.MenuFunction2 callback){ + GenericMenu menu = new GenericMenu(); + + if(topValue != "") + menu.AddItem( new GUIContent(topValue), current == topValue, callback, null ); + + for(int i = 0; i < bones.Count; i++){ + menu.AddItem( new GUIContent(bones[i].Data.Name), bones[i].Data.Name == current, callback, bones[i] ); + } + + menu.ShowAsContext(); + + } + + + void TargetBoneSelected(object obj){ + if(obj == null){ + boneName.stringValue = ""; + serializedObject.ApplyModifiedProperties(); + } + else{ + Bone bone = (Bone)obj; + boneName.stringValue = bone.Data.Name; + serializedObject.ApplyModifiedProperties(); + + utilityBone.Reset(); + } + } + + void SpawnChildBoneSelected(object obj){ + if(obj == null){ + //add recursively + foreach(var bone in utilityBone.bone.Children){ + GameObject go = skeletonUtility.SpawnBoneRecursively( bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale ); + SkeletonUtilityBone[] newUtilityBones = go.GetComponentsInChildren(); + foreach(SkeletonUtilityBone utilBone in newUtilityBones) + SkeletonUtilityInspector.AttachIcon(utilBone); + } + } + else{ + Bone bone = (Bone)obj; + GameObject go = skeletonUtility.SpawnBone( bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale ); + SkeletonUtilityInspector.AttachIcon(go.GetComponent()); + Selection.activeGameObject = go; + EditorGUIUtility.PingObject(go); + } + } + + void SpawnOverride(){ + GameObject go = skeletonUtility.SpawnBone( utilityBone.bone, utilityBone.transform.parent, SkeletonUtilityBone.Mode.Override, utilityBone.position, utilityBone.rotation, utilityBone.scale); + go.name = go.name + " [Override]"; + SkeletonUtilityInspector.AttachIcon(go.GetComponent()); + Selection.activeGameObject = go; + EditorGUIUtility.PingObject(go); + } + + bool CanCreateHingeChain(){ + if(utilityBone == null) return false; + if(utilityBone.rigidbody != null) return false; + if(utilityBone.bone != null && utilityBone.bone.Children.Count == 0) return false; + + Rigidbody[] rigidbodies = utilityBone.GetComponentsInChildren(); + + if(rigidbodies.Length > 0) return false; + + return true; + } + + void CreateHingeChain(){ + var utilBoneArr = utilityBone.GetComponentsInChildren(); + + foreach(var utilBone in utilBoneArr){ + AttachRigidbody(utilBone); + } + + utilityBone.rigidbody.isKinematic = true; + + foreach(var utilBone in utilBoneArr){ + if(utilBone == utilityBone) + continue; + + utilBone.mode = SkeletonUtilityBone.Mode.Override; + + HingeJoint joint = utilBone.gameObject.AddComponent(); + joint.axis = Vector3.forward; + joint.connectedBody = utilBone.transform.parent.rigidbody; + joint.useLimits = true; + JointLimits limits = new JointLimits(); + limits.min = -20; + limits.max = 20; + joint.limits = limits; + utilBone.rigidbody.mass = utilBone.transform.parent.rigidbody.mass * 0.75f; + } + } + + void AttachRigidbody(SkeletonUtilityBone utilBone){ + if(utilBone.GetComponent() == null){ + if(utilBone.bone.Data.Length == 0){ + SphereCollider sphere = utilBone.gameObject.AddComponent(); + sphere.radius = 0.1f; + } + else{ + float length = utilBone.bone.Data.Length; + BoxCollider box = utilBone.gameObject.AddComponent(); + box.size = new Vector3( length, length / 3, 0.2f); + box.center = new Vector3(length / 2, 0, 0); + } + } + + utilBone.gameObject.AddComponent(); + } +} diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs.meta new file mode 100644 index 000000000..340d6e2eb --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3ae20b4bcc31f645afd6f5b64f82473 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs new file mode 100644 index 000000000..7358c7635 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs @@ -0,0 +1,316 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Skeleton Utility created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ + +using UnityEngine; +using UnityEditor; +#if UNITY_4_3 +//nothing +#else +using UnityEditor.AnimatedValues; +#endif +using System.Collections; +using System.Collections.Generic; +using Spine; + +using System.Reflection; + +[CustomEditor(typeof(SkeletonUtility))] +public class SkeletonUtilityInspector : Editor { + + public static void AttachIcon(SkeletonUtilityBone utilityBone){ + Skeleton skeleton = utilityBone.skeletonUtility.skeletonRenderer.skeleton; + Texture2D icon; + if(utilityBone.bone.Data.Length == 0) + icon = SpineEditorUtilities.Icons.nullBone; + else + icon = SpineEditorUtilities.Icons.boneNib; + + foreach(IkConstraint c in skeleton.IkConstraints){ + if(c.Target == utilityBone.bone){ + icon = SpineEditorUtilities.Icons.constraintNib; + break; + } + } + + + + typeof(EditorGUIUtility).InvokeMember("SetIconForObject", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, null, null, new object[2]{ utilityBone.gameObject, icon}); + } + + static void AttachIconsToChildren(Transform root){ + if(root != null){ + var utilityBones = root.GetComponentsInChildren(); + foreach(var utilBone in utilityBones){ + AttachIcon(utilBone); + } + } + } + + + + static SkeletonUtilityInspector(){ + #if UNITY_4_3 + showSlots = false; + #else + showSlots = new AnimBool(false); + #endif + } + + SkeletonUtility skeletonUtility; + + Skeleton skeleton; + SkeletonRenderer skeletonRenderer; + Transform transform; + bool isPrefab; + + + Dictionary> attachmentTable = new Dictionary>(); + + + //GUI stuff +#if UNITY_4_3 + static bool showSlots; +#else + static AnimBool showSlots; +#endif + + void OnEnable(){ + skeletonUtility = (SkeletonUtility)target; + skeletonRenderer = skeletonUtility.GetComponent(); + skeleton = skeletonRenderer.skeleton; + transform = skeletonRenderer.transform; + + if(skeleton == null){ + skeletonRenderer.Reset(); + skeletonRenderer.LateUpdate(); + + skeleton = skeletonRenderer.skeleton; + } + + UpdateAttachments(); + + if(PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab) + isPrefab = true; + + } + + void OnDestroy(){ + + } + + void OnSceneGUI(){ + if(skeleton == null){ + OnEnable(); + return; + } + + float flipRotation = skeleton.FlipX ? -1 : 1; + + foreach(Bone b in skeleton.Bones){ + Vector3 vec = transform.TransformPoint(new Vector3(b.WorldX, b.WorldY, 0)); + + Quaternion rot = Quaternion.Euler(0,0,b.WorldRotation * flipRotation); + Vector3 forward = transform.TransformDirection( rot * Vector3.right); + forward *= flipRotation; + + SpineEditorUtilities.Icons.boneMaterial.SetPass(0); + Graphics.DrawMeshNow( SpineEditorUtilities.Icons.boneMesh, Matrix4x4.TRS ( vec, Quaternion.LookRotation(transform.forward, forward), Vector3.one * b.Data.Length * b.WorldScaleX)); + } + } + + void UpdateAttachments(){ + attachmentTable = new Dictionary>(); + Skin skin = skeleton.Skin; + + if(skin == null){ + skin = skeletonRenderer.skeletonDataAsset.GetSkeletonData(true).DefaultSkin; + } + + for(int i = skeleton.Slots.Count-1; i >= 0; i--){ + List attachments = new List(); + skin.FindAttachmentsForSlot(i, attachments); + + attachmentTable.Add(skeleton.Slots[i], attachments); + } + } + + void SpawnHierarchyButton(string label, string tooltip, SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca, params GUILayoutOption[] options){ + GUIContent content = new GUIContent(label, tooltip); + if(GUILayout.Button(content, options)){ + if(skeletonUtility.skeletonRenderer == null) + skeletonUtility.skeletonRenderer = skeletonUtility.GetComponent(); + + if(skeletonUtility.boneRoot != null){ + return; + } + + skeletonUtility.SpawnHierarchy(mode, pos, rot, sca); + + SkeletonUtilityBone[] boneComps = skeletonUtility.GetComponentsInChildren(); + foreach(SkeletonUtilityBone b in boneComps) + AttachIcon(b); + } + } + + public override void OnInspectorGUI () + { + if(isPrefab){ + GUILayout.Label(new GUIContent("Cannot edit Prefabs", SpineEditorUtilities.Icons.warning)); + return; + } + + skeletonUtility.boneRoot = (Transform)EditorGUILayout.ObjectField( "Bone Root", skeletonUtility.boneRoot, typeof(Transform), true); + + GUILayout.BeginHorizontal(); + EditorGUI.BeginDisabledGroup(skeletonUtility.boneRoot != null); + { + if(GUILayout.Button(new GUIContent("Spawn Hierarchy", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(150), GUILayout.Height(24))) + SpawnHierarchyContextMenu(); + } + EditorGUI.EndDisabledGroup(); + + if(GUILayout.Button(new GUIContent("Spawn Submeshes", SpineEditorUtilities.Icons.subMeshRenderer), GUILayout.Width(150), GUILayout.Height(24))) + skeletonUtility.SpawnSubRenderers(true); + GUILayout.EndHorizontal(); + + EditorGUI.BeginChangeCheck(); + skeleton.FlipX = EditorGUILayout.ToggleLeft("Flip X", skeleton.FlipX); + skeleton.FlipY = EditorGUILayout.ToggleLeft("Flip Y", skeleton.FlipY); + if(EditorGUI.EndChangeCheck()){ + skeletonRenderer.LateUpdate(); + SceneView.RepaintAll(); + } + +#if UNITY_4_3 + showSlots = EditorGUILayout.Foldout(showSlots, "Slots"); +#else + showSlots.target = EditorGUILayout.Foldout(showSlots.target, "Slots"); + if(EditorGUILayout.BeginFadeGroup(showSlots.faded)){ +#endif + foreach(KeyValuePair> pair in attachmentTable){ + + Slot slot = pair.Key; + + EditorGUILayout.BeginHorizontal(); + EditorGUI.indentLevel = 1; + EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, SpineEditorUtilities.Icons.slot), GUILayout.ExpandWidth(false)); + + EditorGUI.BeginChangeCheck(); + Color c = EditorGUILayout.ColorField(new Color(slot.R, slot.G, slot.B, slot.A), GUILayout.Width(60)); + + if(EditorGUI.EndChangeCheck()){ + slot.SetColor( c ); + skeletonRenderer.LateUpdate(); + } + + EditorGUILayout.EndHorizontal(); + + + + foreach(Attachment attachment in pair.Value){ + + if(slot.Attachment == attachment){ + GUI.contentColor = Color.white; + } + else{ + GUI.contentColor = Color.grey; + } + + EditorGUI.indentLevel = 2; + bool isAttached = attachment == slot.Attachment; + + Texture2D icon = null; + + if(attachment is MeshAttachment || attachment is SkinnedMeshAttachment) + icon = SpineEditorUtilities.Icons.mesh; + else + icon = SpineEditorUtilities.Icons.image; + + bool swap = EditorGUILayout.ToggleLeft( new GUIContent( attachment.Name, icon ), attachment == slot.Attachment ); + + if(!isAttached && swap){ + slot.Attachment = attachment; + skeletonRenderer.LateUpdate(); + } + else if(isAttached && !swap){ + slot.Attachment = null; + skeletonRenderer.LateUpdate(); + } + + GUI.contentColor = Color.white; + } + } + #if UNITY_4_3 + +#else + } + EditorGUILayout.EndFadeGroup(); + if(showSlots.isAnimating) + Repaint(); +#endif + } + + void SpawnHierarchyContextMenu(){ + GenericMenu menu = new GenericMenu(); + + menu.AddItem(new GUIContent("Follow"), false, SpawnFollowHierarchy); + menu.AddItem(new GUIContent("Follow (Root Only)"), false, SpawnFollowHierarchyRootOnly); + menu.AddSeparator(""); + menu.AddItem(new GUIContent("Override"), false, SpawnOverrideHierarchy); + menu.AddItem(new GUIContent("Override (Root Only)"), false, SpawnOverrideHierarchyRootOnly); + + menu.ShowAsContext(); + } + + void SpawnFollowHierarchy(){ + Selection.activeGameObject = skeletonUtility.SpawnHierarchy( SkeletonUtilityBone.Mode.Follow, true, true, true ); + AttachIconsToChildren( skeletonUtility.boneRoot ); + } + + void SpawnFollowHierarchyRootOnly(){ + Selection.activeGameObject = skeletonUtility.SpawnRoot( SkeletonUtilityBone.Mode.Follow, true, true, true ); + AttachIconsToChildren( skeletonUtility.boneRoot ); + } + + void SpawnOverrideHierarchy(){ + Selection.activeGameObject = skeletonUtility.SpawnHierarchy( SkeletonUtilityBone.Mode.Override, true, true, true ); + AttachIconsToChildren( skeletonUtility.boneRoot ); + } + + void SpawnOverrideHierarchyRootOnly(){ + Selection.activeGameObject = skeletonUtility.SpawnRoot( SkeletonUtilityBone.Mode.Override, true, true, true ); + AttachIconsToChildren( skeletonUtility.boneRoot ); + } +} diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs.meta new file mode 100644 index 000000000..7820cbd6d --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a5b90df955eb8c2429ac67c8b2de6c5c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs new file mode 100644 index 000000000..1813512a7 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs @@ -0,0 +1,335 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Skeleton Utility created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ + +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using Spine; + +[RequireComponent(typeof(SkeletonAnimation))] +[ExecuteInEditMode] +public class SkeletonUtility : MonoBehaviour { + public delegate void SkeletonUtilityDelegate(); + public event SkeletonUtilityDelegate OnReset; + + public Transform boneRoot; + + void Update(){ + if(boneRoot != null && skeletonRenderer.skeleton != null){ + Vector3 flipScale = Vector3.one; + if(skeletonRenderer.skeleton.FlipX) + flipScale.x = -1; + + if(skeletonRenderer.skeleton.FlipY) + flipScale.y = -1; + + boneRoot.localScale = flipScale; + } + } + + [HideInInspector] + public SkeletonRenderer skeletonRenderer; + + [HideInInspector] + public SkeletonAnimation skeletonAnimation; + + [System.NonSerialized] + public List utilityBones = new List(); + + [System.NonSerialized] + public List utilityConstraints = new List(); +// Dictionary utilityBoneTable; + + + protected bool hasTransformBones; + protected bool hasUtilityConstraints; + protected bool needToReprocessBones; + + void OnEnable(){ + if(skeletonRenderer == null){ + skeletonRenderer = GetComponent(); + } + + if(skeletonAnimation == null){ + skeletonAnimation = GetComponent(); + } + + skeletonRenderer.OnReset -= HandleRendererReset; + skeletonRenderer.OnReset += HandleRendererReset; + + if(skeletonAnimation != null){ + skeletonAnimation.UpdateLocal -= UpdateLocal; + skeletonAnimation.UpdateLocal += UpdateLocal; + } + + + CollectBones(); + } + + void Start(){ + //recollect because order of operations failure when switching between game mode and edit mode... +// CollectBones(); + } + + + + void OnDisable(){ + skeletonRenderer.OnReset -= HandleRendererReset; + + if(skeletonAnimation != null){ + skeletonAnimation.UpdateLocal -= UpdateLocal; + skeletonAnimation.UpdateWorld -= UpdateWorld; + skeletonAnimation.UpdateComplete -= UpdateComplete; + } + } + + void HandleRendererReset(SkeletonRenderer r){ + if(OnReset != null) + OnReset(); + + CollectBones(); + } + + public void RegisterBone(SkeletonUtilityBone bone){ + if(utilityBones.Contains(bone)) + return; + else{ + utilityBones.Add(bone); + needToReprocessBones = true; + } + } + + public void UnregisterBone(SkeletonUtilityBone bone){ + utilityBones.Remove(bone); + } + + public void RegisterConstraint(SkeletonUtilityConstraint constraint){ + + if(utilityConstraints.Contains(constraint)) + return; + else{ + utilityConstraints.Add(constraint); + needToReprocessBones = true; + } + } + + public void UnregisterConstraint(SkeletonUtilityConstraint constraint){ + utilityConstraints.Remove(constraint); + } + + public void CollectBones(){ + if(skeletonRenderer.skeleton == null) + return; + + if(boneRoot != null){ + List constraintTargetNames = new List(); + + foreach(IkConstraint c in skeletonRenderer.skeleton.IkConstraints){ + constraintTargetNames.Add(c.Target.Data.Name); + } + + foreach(var b in utilityBones){ + if(b.bone == null){ + return; + } + if(b.mode == SkeletonUtilityBone.Mode.Override){ + hasTransformBones = true; + } + + if(constraintTargetNames.Contains( b.bone.Data.Name )){ + hasUtilityConstraints = true; + } + } + + if(utilityConstraints.Count > 0) + hasUtilityConstraints = true; + + if(skeletonAnimation != null){ + skeletonAnimation.UpdateWorld -= UpdateWorld; + skeletonAnimation.UpdateComplete -= UpdateComplete; + + if(hasTransformBones || hasUtilityConstraints){ + skeletonAnimation.UpdateWorld += UpdateWorld; + } + + if(hasUtilityConstraints){ + skeletonAnimation.UpdateComplete += UpdateComplete; + } + } + + needToReprocessBones = false; + } + else{ + utilityBones.Clear(); + utilityConstraints.Clear(); + } + + } + + void UpdateLocal(SkeletonAnimation anim){ + + if(needToReprocessBones) + CollectBones(); + + if(utilityBones == null) + return; + + foreach(SkeletonUtilityBone b in utilityBones){ + b.transformLerpComplete = false; + } + + UpdateAllBones(); + } + + void UpdateWorld(SkeletonAnimation anim){ + UpdateAllBones(); + + foreach(SkeletonUtilityConstraint c in utilityConstraints) + c.DoUpdate(); + } + + void UpdateComplete(SkeletonAnimation anim){ + UpdateAllBones(); + } + + void UpdateAllBones(){ + if(boneRoot == null){ + CollectBones(); + } + + if(utilityBones == null) + return; + + foreach(SkeletonUtilityBone b in utilityBones){ + b.DoUpdate(); + } + } + + public Transform GetBoneRoot(){ + if(boneRoot != null) + return boneRoot; + + boneRoot = new GameObject("SkeletonUtility-Root").transform; + boneRoot.parent = transform; + boneRoot.localPosition = Vector3.zero; + boneRoot.localRotation = Quaternion.identity; + boneRoot.localScale = Vector3.one; + + return boneRoot; + } + + public GameObject SpawnRoot(SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca){ + GetBoneRoot(); + Skeleton skeleton = this.skeletonRenderer.skeleton; + + GameObject go = SpawnBone( skeleton.RootBone, boneRoot, mode, pos, rot, sca ); + + CollectBones(); + + return go; + } + + public GameObject SpawnHierarchy(SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca){ + GetBoneRoot(); + + Skeleton skeleton = this.skeletonRenderer.skeleton; + + GameObject go = SpawnBoneRecursively(skeleton.RootBone, boneRoot, mode, pos, rot, sca); + + CollectBones(); + + return go; + } + + public GameObject SpawnBoneRecursively(Bone bone, Transform parent, SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca){ + GameObject go = SpawnBone(bone, parent, mode, pos, rot, sca); + + foreach(Bone child in bone.Children){ + SpawnBoneRecursively(child, go.transform, mode, pos, rot, sca); + } + + return go; + } + + public GameObject SpawnBone(Bone bone, Transform parent, SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca){ + GameObject go = new GameObject(bone.Data.Name); + go.transform.parent = parent; + + SkeletonUtilityBone b = go.AddComponent(); + b.skeletonUtility = this; + b.position = pos; + b.rotation = rot; + b.scale = sca; + b.mode = mode; + b.zPosition = true; + b.Reset(); + b.bone = bone; + b.boneName = bone.Data.Name; + b.valid = true; + + if(mode == SkeletonUtilityBone.Mode.Override){ + if(rot) + go.transform.localRotation = Quaternion.Euler(0, 0, b.bone.RotationIK); + + if(pos) + go.transform.localPosition = new Vector3(b.bone.X, b.bone.Y, 0); + + go.transform.localScale = new Vector3(b.bone.scaleX, b.bone.scaleY, 0); + } + + return go; + } + + public void SpawnSubRenderers(bool disablePrimaryRenderer){ + int submeshCount = GetComponent().sharedMesh.subMeshCount; + + for(int i = 0; i < submeshCount; i++){ + GameObject go = new GameObject("Submesh " + i, typeof(MeshFilter), typeof(MeshRenderer)); + go.transform.parent = transform; + go.transform.localPosition = Vector3.zero; + go.transform.localRotation = Quaternion.identity; + go.transform.localScale = Vector3.one; + + SkeletonUtilitySubmeshRenderer s = go.AddComponent(); + s.sortingOrder = i * 10; + s.submeshIndex = i; + s.Initialize( renderer ); + s.Update(); + } + + if(disablePrimaryRenderer) + renderer.enabled = false; + } +} diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs.meta new file mode 100644 index 000000000..7d3d7a44f --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f726fb798ad621458c431cb9966d91d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs new file mode 100644 index 000000000..51dee1cc6 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs @@ -0,0 +1,218 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Skeleton Utility created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ + +using System; +using System.IO; +using System.Collections.Generic; +using UnityEngine; +using Spine; + +/// Sets a GameObject's transform to match a bone on a Spine skeleton. +[ExecuteInEditMode] +[AddComponentMenu("Spine/SkeletonUtilityBone")] +public class SkeletonUtilityBone : MonoBehaviour { + + public enum Mode { Follow, Override } + + [System.NonSerialized] + public bool valid; + + [System.NonSerialized] + public SkeletonUtility skeletonUtility; + + [System.NonSerialized] + public Bone bone; + + public Mode mode; + + public bool zPosition = true; + public bool position; + public bool rotation; + public bool scale; + + [Range(0f,1f)] + public float overrideAlpha = 1; + + /// If a bone isn't set, boneName is used to find the bone. + public String boneName; + + public Transform parentReference; + + [HideInInspector] + public bool transformLerpComplete; + + protected Transform cachedTransform; + protected Transform skeletonTransform; + + public bool NonUniformScaleWarning{ + get{ + return nonUniformScaleWarning; + } + } + private bool nonUniformScaleWarning; + + public void Reset () { + bone = null; + cachedTransform = transform; + valid = skeletonUtility != null && skeletonUtility.skeletonRenderer != null && skeletonUtility.skeletonRenderer.valid; + if (!valid) return; + skeletonTransform = skeletonUtility.transform; + + skeletonUtility.OnReset -= HandleOnReset; + skeletonUtility.OnReset += HandleOnReset; + + DoUpdate(); + } + + void OnEnable(){ + skeletonUtility = GetComponentInParent(); + if(skeletonUtility == null) + return; + + skeletonUtility.RegisterBone(this); + + skeletonUtility.OnReset += HandleOnReset; + } + + void HandleOnReset () + { + Reset (); + } + + void OnDisable(){ + if(skeletonUtility != null){ + skeletonUtility.OnReset -= HandleOnReset; + + skeletonUtility.UnregisterBone(this); + } + } + + public void DoUpdate () { + + if (!valid) { + Reset(); + return; + } + + Spine.Skeleton skeleton = skeletonUtility.skeletonRenderer.skeleton; + + if (bone == null) { + if (boneName == null || boneName.Length == 0) return; + bone = skeleton.FindBone(boneName); + if (bone == null) { + Debug.LogError("Bone not found: " + boneName, this); + return; + } + } + + + float flipRotation = (skeleton.flipX ^ skeleton.flipY) ? -1f : 1f; + + + if(mode == Mode.Follow){ + if(position){ + cachedTransform.localPosition = new Vector3(bone.x, bone.y, 0); + } + + if(rotation){ + + if(bone.Data.InheritRotation){ + cachedTransform.localRotation = Quaternion.Euler(0,0,bone.rotationIK); + } + else{ + Vector3 euler = skeletonTransform.rotation.eulerAngles; + cachedTransform.rotation = Quaternion.Euler(euler.x, euler.y, skeletonTransform.rotation.eulerAngles.z + (bone.worldRotation * flipRotation) ); + } + + } + + if(scale){ + cachedTransform.localScale = new Vector3(bone.scaleX, bone.scaleY, 1); + + nonUniformScaleWarning = (bone.scaleX != bone.scaleY); + } + + } + else if(mode == Mode.Override){ + if(transformLerpComplete) + return; + + if(parentReference == null){ + if(position){ + bone.x = Mathf.Lerp(bone.x, cachedTransform.localPosition.x, overrideAlpha); + bone.y = Mathf.Lerp(bone.y, cachedTransform.localPosition.y, overrideAlpha); + } + + if(rotation){ + bone.rotation = Mathf.LerpAngle(bone.Rotation, cachedTransform.localRotation.eulerAngles.z, overrideAlpha); + } + + if(scale){ + bone.scaleX = Mathf.Lerp(bone.scaleX, cachedTransform.localScale.x, overrideAlpha); + bone.scaleY = Mathf.Lerp(bone.scaleY, cachedTransform.localScale.y, overrideAlpha); + + nonUniformScaleWarning = (bone.scaleX != bone.scaleY); + } + } + else{ + if(position){ + Vector3 pos = parentReference.InverseTransformPoint(cachedTransform.position); + bone.x = Mathf.Lerp(bone.x, pos.x, overrideAlpha); + bone.y = Mathf.Lerp(bone.y, pos.y, overrideAlpha); + } + + if(rotation){ + bone.rotation = Mathf.LerpAngle(bone.Rotation, Quaternion.LookRotation( Vector3.forward, parentReference.InverseTransformDirection( cachedTransform.up ) ).eulerAngles.z, overrideAlpha); + } + + //TODO: Something about this + if(scale){ + bone.scaleX = Mathf.Lerp(bone.scaleX, cachedTransform.localScale.x, overrideAlpha); + bone.scaleY = Mathf.Lerp(bone.scaleY, cachedTransform.localScale.y, overrideAlpha); + + nonUniformScaleWarning = (bone.scaleX != bone.scaleY); + } + } + + transformLerpComplete = true; + } + } + + void OnDrawGizmos(){ + if(NonUniformScaleWarning){ + Gizmos.DrawIcon(transform.position + new Vector3(0,0.128f,0), "icon-warning"); + } + } +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs.meta new file mode 100644 index 000000000..f66d45053 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b238dfcde8209044b97d23f62bcaadf6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs new file mode 100644 index 000000000..ffdcf1dd3 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs @@ -0,0 +1,22 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] + +public abstract class SkeletonUtilityConstraint : MonoBehaviour { + + protected SkeletonUtilityBone utilBone; + protected SkeletonUtility skeletonUtility; + + protected virtual void OnEnable(){ + utilBone = GetComponent(); + skeletonUtility = GetComponentInParent(); + skeletonUtility.RegisterConstraint(this); + } + + protected virtual void OnDisable(){ + skeletonUtility.UnregisterConstraint(this); + } + + public abstract void DoUpdate(); +} diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs.meta new file mode 100644 index 000000000..dad11e0a2 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 522dbfcc6c916df4396f14f35048d185 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityEyeConstraint.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityEyeConstraint.cs new file mode 100644 index 000000000..07203faef --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityEyeConstraint.cs @@ -0,0 +1,61 @@ +using UnityEngine; +using System.Collections; + +public class SkeletonUtilityEyeConstraint : SkeletonUtilityConstraint { + + public Transform[] eyes; + public float radius = 0.5f; + public Transform target; + public Vector3 targetPosition; + + public float speed = 10; + + Vector3[] origins; + Vector3 centerPoint; + + protected override void OnEnable () + { + if(!Application.isPlaying) + return; + + base.OnEnable (); + + Bounds centerBounds = new Bounds( eyes[0].localPosition, Vector3.zero ); + origins = new Vector3[eyes.Length]; + for(int i = 0; i < eyes.Length; i++){ + origins[i] = eyes[i].localPosition; + centerBounds.Encapsulate( origins[i] ); + } + + centerPoint = centerBounds.center; + } + + protected override void OnDisable () + { + if(!Application.isPlaying) + return; + + base.OnDisable (); + } + + public override void DoUpdate () + { + + if(target != null) + targetPosition = target.position; + + Vector3 goal = targetPosition; + + Vector3 center = transform.TransformPoint(centerPoint); + Vector3 dir = goal - center; + + if(dir.magnitude > 1) + dir.Normalize(); + + for(int i = 0; i < eyes.Length; i++){ + center = transform.TransformPoint(origins[i]); + eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius), speed * Time.deltaTime); + } + + } +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityEyeConstraint.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityEyeConstraint.cs.meta new file mode 100644 index 000000000..3e82746da --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityEyeConstraint.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0d994c65b6daec64f80ae2ae04e9d999 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityGroundConstraint.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityGroundConstraint.cs new file mode 100644 index 000000000..70301d92d --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityGroundConstraint.cs @@ -0,0 +1,58 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] +public class SkeletonUtilityGroundConstraint : SkeletonUtilityConstraint { + + public LayerMask groundMask; + public bool use2D = true; + public float castDistance = 5f; + Vector3 rayOrigin; + Vector3 rayDir = new Vector3(0,-1,0); + float hitY; + + protected override void OnEnable () + { + base.OnEnable (); + } + + protected override void OnDisable () + { + base.OnDisable (); + } + + public override void DoUpdate() + { + rayOrigin = transform.position + new Vector3(0,castDistance,0); + + hitY = float.MinValue; + if(use2D){ + RaycastHit2D hit = Physics2D.Raycast(rayOrigin , rayDir, castDistance, groundMask); + if(hit.collider != null){ + hitY = hit.point.y; + } + } + else{ + RaycastHit hit; + if(Physics.Raycast( rayOrigin, rayDir, out hit, castDistance, groundMask)){ + hitY = hit.point.y; + } + } + + Vector3 v = transform.position; + v.y = Mathf.Clamp(v.y, hitY, float.MaxValue); + transform.position = v; + + utilBone.bone.X = transform.localPosition.x; + utilBone.bone.Y = transform.localPosition.y; + + } + + void OnDrawGizmos(){ + Vector3 hitEnd = rayOrigin + (rayDir * Mathf.Min(castDistance, rayOrigin.y - hitY)); + Vector3 clearEnd = rayOrigin + (rayDir * castDistance); + Gizmos.DrawLine(rayOrigin, hitEnd); + Gizmos.color = Color.red; + Gizmos.DrawLine(hitEnd, clearEnd); + } +} diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityGroundConstraint.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityGroundConstraint.cs.meta new file mode 100644 index 000000000..5d9e6920c --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityGroundConstraint.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3662334b99de5fe4396ab24e30c4fd12 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs new file mode 100644 index 000000000..917eb5a45 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs @@ -0,0 +1,81 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +public class SkeletonUtilityKinematicShadow : MonoBehaviour { + + public bool hideShadow = true; + + Dictionary shadowTable; + GameObject shadowRoot; + + void Start(){ + shadowRoot = (GameObject)Instantiate(gameObject); + if(hideShadow) + shadowRoot.hideFlags = HideFlags.HideInHierarchy; + + shadowRoot.transform.parent = transform.root; + + shadowTable = new Dictionary(); + + Destroy(shadowRoot.GetComponent()); + + shadowRoot.transform.position = transform.position; + shadowRoot.transform.rotation = transform.rotation; + + Vector3 scaleRef = transform.TransformPoint(Vector3.right); + float scale = Vector3.Distance(transform.position, scaleRef); + shadowRoot.transform.localScale = Vector3.one; + + var shadowJoints = shadowRoot.GetComponentsInChildren(); + foreach(Joint j in shadowJoints){ + j.connectedAnchor *= scale; + } + + var joints = GetComponentsInChildren(); + foreach(var j in joints) + Destroy(j); + + var rbs = GetComponentsInChildren(); + foreach(var rb in rbs) + Destroy(rb); + + var colliders = GetComponentsInChildren(); + foreach(var c in colliders) + Destroy(c); + + + //match by bone name + var shadowBones = shadowRoot.GetComponentsInChildren(); + var bones = GetComponentsInChildren(); + + //build bone lookup + foreach(var b in bones){ + if(b.gameObject == gameObject) + continue; + + foreach(var sb in shadowBones){ + if(sb.rigidbody == null) + continue; + + if(sb.boneName == b.boneName){ + shadowTable.Add( sb.transform, b.transform ); + break; + } + } + } + + foreach(var b in shadowBones) + Destroy(b); + } + + void FixedUpdate(){ + shadowRoot.rigidbody.MovePosition( transform.position ); + shadowRoot.rigidbody.MoveRotation( transform.rotation ); + + foreach(var pair in shadowTable){ + pair.Value.localPosition = pair.Key.localPosition; + pair.Value.localRotation = pair.Key.localRotation; + } + } +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs.meta new file mode 100644 index 000000000..06bcb6f4a --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cfeac06b8a6aa1645813700e3e4c0863 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs new file mode 100644 index 000000000..f6a2e682b --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs @@ -0,0 +1,102 @@ +using UnityEngine; +using System.Collections; + +[ExecuteInEditMode] +public class SkeletonUtilitySubmeshRenderer : MonoBehaviour { + + public Renderer parentRenderer; + + [System.NonSerialized] + public Mesh mesh; + + public int submeshIndex = 0; + public int sortingOrder = 0; + public int sortingLayerID = 0; + + public Material hiddenPassMaterial; + Renderer cachedRenderer; + MeshFilter filter; + Material[] sharedMaterials; + MeshFilter parentFilter; + + void Awake(){ + cachedRenderer = renderer; + sharedMaterials = cachedRenderer.sharedMaterials; + filter = GetComponent(); + + if(parentRenderer != null) + Initialize( parentRenderer ); + } + + void OnEnable(){ + parentRenderer = transform.parent.GetComponent(); + parentRenderer.GetComponent().OnReset += HandleSkeletonReset; + } + + void OnDisable(){ + parentRenderer.GetComponent().OnReset -= HandleSkeletonReset; + } + + void HandleSkeletonReset(SkeletonRenderer r){ + if(parentRenderer != null) + Initialize(parentRenderer); + } + + public void Initialize(Renderer parentRenderer){ + this.parentRenderer = parentRenderer; + parentFilter = parentRenderer.GetComponent(); + mesh = parentFilter.sharedMesh; + filter.sharedMesh = mesh; + Debug.Log("Mesh: " + mesh); + } + + public void Update(){ + if(mesh == null || mesh != parentFilter.sharedMesh){ + mesh = parentFilter.sharedMesh; + filter.sharedMesh = mesh; + } + + if(cachedRenderer == null) + cachedRenderer = renderer; + + if(mesh == null || submeshIndex > mesh.subMeshCount - 1){ + cachedRenderer.enabled = false; + return; + } + else{ + renderer.enabled = true; + } + + bool changed = false; + + if(sharedMaterials.Length != parentRenderer.sharedMaterials.Length){ + sharedMaterials = parentRenderer.sharedMaterials; + changed = true; + } + + + + for(int i = 0; i < renderer.sharedMaterials.Length; i++){ + if(i == submeshIndex) + continue; + + if(sharedMaterials[i] != hiddenPassMaterial){ + sharedMaterials[i] = hiddenPassMaterial; + changed = true; + } + } + + if(sharedMaterials[submeshIndex] != parentRenderer.sharedMaterials[submeshIndex]){ + sharedMaterials[submeshIndex] = parentRenderer.sharedMaterials[submeshIndex]; + changed = true; + } + + if(changed){ + cachedRenderer.sharedMaterials = sharedMaterials; + } + + + cachedRenderer.sortingLayerID = sortingLayerID; + cachedRenderer.sortingOrder = sortingOrder; + } +} diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs.meta b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs.meta new file mode 100644 index 000000000..168ca8811 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7820c1c2b0e52c6408de899d6939996e +MonoImporter: + serializedVersion: 2 + defaultReferences: + - parentRenderer: {instanceID: 0} + - mesh: {instanceID: 0} + - hiddenPassMaterial: {fileID: 2100000, guid: 43227e5adadc6f24bb4bf74b92a56fb4, + type: 2} + executionOrder: 0 + icon: {instanceID: 0} + userData: