├── README.md ├── spine-csharp ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── nuget │ └── Spine.1.6.18.nuspec └── src │ ├── Animation.cs │ ├── AnimationState.cs │ ├── AnimationStateData.cs │ ├── Atlas.cs │ ├── Attachments │ ├── AtlasAttachmentLoader.cs │ ├── Attachment.cs │ ├── AttachmentLoader.cs │ ├── AttachmentType.cs │ ├── BoundingBoxAttachment.cs │ ├── MeshAttachment.cs │ ├── RegionAttachment.cs │ └── SkinnedMeshAttachment.cs │ ├── Bone.cs │ ├── BoneData.cs │ ├── Event.cs │ ├── EventData.cs │ ├── IkConstraint.cs │ ├── IkConstraintData.cs │ ├── Json.cs │ ├── Skeleton.cs │ ├── SkeletonBinary.cs │ ├── SkeletonBounds.cs │ ├── SkeletonData.cs │ ├── SkeletonJson.cs │ ├── Skin.cs │ ├── Slot.cs │ └── SlotData.cs └── spine-unity ├── AtlasAsset.cs ├── AtlasRegionAttacher.cs ├── BoneFollower.cs ├── CustomSkin.cs ├── Editor ├── AtlasAssetInspector.cs ├── BoneFollowerInspector.cs ├── GUI │ ├── icon-animation.png │ ├── icon-animationRoot.png │ ├── icon-bone.png │ ├── icon-boneNib.png │ ├── icon-boundingBox.png │ ├── icon-constraintNib.png │ ├── icon-event.png │ ├── icon-hingeChain.png │ ├── icon-image.png │ ├── icon-mesh.png │ ├── icon-null.png │ ├── icon-poseBones.png │ ├── icon-skeleton.png │ ├── icon-skeletonUtility.png │ ├── icon-skin.png │ ├── icon-skinPlaceholder.png │ ├── icon-skinsRoot.png │ ├── icon-slot.png │ ├── icon-slotRoot.png │ ├── icon-spine.png │ ├── icon-subMeshRenderer.png │ ├── icon-warning.png │ └── icon-weights.png ├── Menus.cs ├── SkeletonAnimationInspector.cs ├── SkeletonAnimatorInspector.cs ├── SkeletonBaker.cs ├── SkeletonDataAssetInspector.cs ├── SkeletonRendererInspector.cs ├── SpineAttributeDrawers.cs └── SpineEditorUtilities.cs ├── Shaders ├── Bones.shader ├── HiddenPass.mat ├── HiddenPass.shader ├── SkeletonLit.shader ├── Spine-Skeleton-BlendMode.shader ├── Spine-Skeleton-HDR.shader └── Spine-Skeleton.shader ├── SkeletonAnimation.cs ├── SkeletonAnimationInterface.cs ├── SkeletonAnimator.cs ├── SkeletonDataAsset.cs ├── SkeletonExtensions.cs ├── SkeletonRenderer.cs ├── SkeletonUtility ├── Editor │ ├── SkeletonUtilityBoneInspector.cs │ ├── SkeletonUtilityInspector.cs │ └── SkeletonUtilitySubmeshRendererInspector.cs ├── SkeletonUtility.cs ├── SkeletonUtilityBone.cs ├── SkeletonUtilityConstraint.cs ├── SkeletonUtilityEyeConstraint.cs ├── SkeletonUtilityGroundConstraint.cs ├── SkeletonUtilityKinematicShadow.cs └── SkeletonUtilitySubmeshRenderer.cs ├── SpineAttributes.cs ├── SpriteAttacher.cs └── SpriteCollectionAttachmentLoader.cs /README.md: -------------------------------------------------------------------------------- 1 | # spine-optimize 2 | Spine for Unity Version 2.1 3 | 4 | First: 5 | Convert JSON to binary. 6 | 7 | Second: 8 | Use pointer movement instead of Stream read. 9 | 10 | Once again, to optimize: 11 | All strings moved to the header, using index instead. 12 | Delete nonessential data. 13 | Merge Timeline. 14 | So the binary 50%-70% smaller. 15 | 16 | spine版本比较老2.1,但优化原理一样。 17 | 第一步:读取json格式转成二进制。 18 | 第二步:使用指针代替Stream读取。 19 | 第三步:将所有的string移到头部,使用下标代替,合并相同的timeline。 20 | 这样可以使二进制再小50%-70%。 -------------------------------------------------------------------------------- /spine-csharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | 9 | // Setting ComVisible to false makes the types in this assembly not visible 10 | // to COM components. If you need to access a type in this assembly from 11 | // COM, set the ComVisible attribute to true on that type. Only Windows 12 | // assemblies support COM. 13 | [assembly: ComVisible(false)] 14 | 15 | // On Windows, the following GUID is for the ID of the typelib if this 16 | // project is exposed to COM. On other platforms, it unique identifies the 17 | // title storage container when deploying this assembly to the device. 18 | [assembly: Guid("3ac8567e-9ae8-4624-87b9-a84f0101c629")] 19 | 20 | // Version information for an assembly consists of the following four values: 21 | // 22 | // Major Version 23 | // Minor Version 24 | // Build Number 25 | // Revision 26 | // -------------------------------------------------------------------------------- /spine-csharp/README.md: -------------------------------------------------------------------------------- 1 | # spine-csharp 2 | 3 | The spine-csharp runtime provides functionality to load and manipulate [Spine](http://esotericsoftware.com) skeletal animation data using C# (C Sharp). It does not perform rendering but can be extended to enable Spine animations for other C#-based projects. 4 | 5 | ## Setup 6 | 7 | 1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip). 8 | 1. Open the `spine-csharp.sln` Visual C# 2010 Express project file. 9 | 10 | Alternatively, the contents of the `spine-csharp/src` directory can be copied into your project. 11 | 12 | ## Runtimes Extending spine-csharp 13 | 14 | - [spine-monogame](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-monogame) 15 | - [spine-tk2d](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-tk2d) 16 | - [spine-unity](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-unity) 17 | - [spine-xna](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-xna) 18 | -------------------------------------------------------------------------------- /spine-csharp/nuget/Spine.1.6.18.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spine 5 | 1.6.18.0 6 | Esoteric Software 7 | Esoteric Software 8 | https://github.com/EsotericSoftware/spine-runtimes/blob/master/LICENSE 9 | http://esotericsoftware.com/ 10 | http://esotericsoftware.com/spine/files/logo-420.png 11 | true 12 | Spine is a 2D skeletal animation tool for game development and other animation projects. 13 | Spine features an intuitive workflow to rig and animate skeletons, a multiple-timeline dopesheet for retiming and tweaking animations, powerful exporting capabilities, and runtimes for many programming languages and game toolkits. 14 | Release build for .NET 4.0 of version 1.6.18 (changeset c732a687, 2013-10-24) 15 | Copyright 2013 16 | 2D skeletal animation runtime Spine 17 | 18 | -------------------------------------------------------------------------------- /spine-csharp/src/AnimationStateData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class AnimationStateData { 36 | internal SkeletonData skeletonData; 37 | private Dictionary, float> animationToMixTime = new Dictionary, float>(); 38 | internal float defaultMix; 39 | 40 | public SkeletonData SkeletonData { get { return skeletonData; } } 41 | public float DefaultMix { get { return defaultMix; } set { defaultMix = value; } } 42 | 43 | public AnimationStateData (SkeletonData skeletonData) { 44 | this.skeletonData = skeletonData; 45 | } 46 | 47 | public void SetMix (String fromName, String toName, float duration) { 48 | Animation from = skeletonData.FindAnimation(fromName); 49 | if (from == null) throw new ArgumentException("Animation not found: " + fromName); 50 | Animation to = skeletonData.FindAnimation(toName); 51 | if (to == null) throw new ArgumentException("Animation not found: " + toName); 52 | SetMix(from, to, duration); 53 | } 54 | 55 | public void SetMix (Animation from, Animation to, float duration) { 56 | if (from == null) throw new ArgumentNullException("from cannot be null."); 57 | if (to == null) throw new ArgumentNullException("to cannot be null."); 58 | KeyValuePair key = new KeyValuePair(from, to); 59 | animationToMixTime.Remove(key); 60 | animationToMixTime.Add(key, duration); 61 | } 62 | 63 | public float GetMix (Animation from, Animation to) { 64 | KeyValuePair key = new KeyValuePair(from, to); 65 | float duration; 66 | if (animationToMixTime.TryGetValue(key, out duration)) return duration; 67 | return defaultMix; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/AtlasAttachmentLoader.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class AtlasAttachmentLoader : AttachmentLoader { 36 | private Atlas[] atlasArray; 37 | 38 | // HuaHua. cache regions, quickly find 39 | private Dictionary regins = new Dictionary(); 40 | 41 | public AtlasAttachmentLoader(params Atlas[] atlasArray) 42 | { 43 | if (atlasArray == null) throw new ArgumentNullException("atlas array cannot be null."); 44 | this.atlasArray = atlasArray; 45 | 46 | // HuaHua. 47 | for (int i = 0; i < atlasArray.Length; i++) 48 | { 49 | var regions = atlasArray[i].regions; 50 | 51 | for (int ir = 0, n = regions.Count; ir < n; ir++) 52 | { 53 | regins.Add(regions[ir].name, regions[ir]); 54 | } 55 | } 56 | } 57 | 58 | public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { 59 | AtlasRegion region = FindRegion(path); 60 | if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")"); 61 | RegionAttachment attachment = new RegionAttachment(name); 62 | attachment.RendererObject = region; 63 | attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); 64 | attachment.regionOffsetX = region.offsetX; 65 | attachment.regionOffsetY = region.offsetY; 66 | attachment.regionWidth = region.width; 67 | attachment.regionHeight = region.height; 68 | attachment.regionOriginalWidth = region.originalWidth; 69 | attachment.regionOriginalHeight = region.originalHeight; 70 | return attachment; 71 | } 72 | 73 | public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { 74 | AtlasRegion region = FindRegion(path); 75 | if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); 76 | MeshAttachment attachment = new MeshAttachment(name); 77 | attachment.RendererObject = region; 78 | attachment.RegionU = region.u; 79 | attachment.RegionV = region.v; 80 | attachment.RegionU2 = region.u2; 81 | attachment.RegionV2 = region.v2; 82 | attachment.RegionRotate = region.rotate; 83 | attachment.regionOffsetX = region.offsetX; 84 | attachment.regionOffsetY = region.offsetY; 85 | attachment.regionWidth = region.width; 86 | attachment.regionHeight = region.height; 87 | attachment.regionOriginalWidth = region.originalWidth; 88 | attachment.regionOriginalHeight = region.originalHeight; 89 | return attachment; 90 | } 91 | 92 | public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path) { 93 | AtlasRegion region = FindRegion(path); 94 | if (region == null) throw new Exception("Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")"); 95 | SkinnedMeshAttachment attachment = new SkinnedMeshAttachment(name); 96 | attachment.RendererObject = region; 97 | attachment.RegionU = region.u; 98 | attachment.RegionV = region.v; 99 | attachment.RegionU2 = region.u2; 100 | attachment.RegionV2 = region.v2; 101 | attachment.RegionRotate = region.rotate; 102 | attachment.regionOffsetX = region.offsetX; 103 | attachment.regionOffsetY = region.offsetY; 104 | attachment.regionWidth = region.width; 105 | attachment.regionHeight = region.height; 106 | attachment.regionOriginalWidth = region.originalWidth; 107 | attachment.regionOriginalHeight = region.originalHeight; 108 | return attachment; 109 | } 110 | 111 | public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { 112 | return new BoundingBoxAttachment(name); 113 | } 114 | 115 | public AtlasRegion FindRegion(string name) { 116 | regins.TryGetValue(name, out AtlasRegion region); 117 | return region; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/Attachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | abstract public class Attachment { 35 | public String Name { get; private set; } 36 | 37 | public Attachment (String name) { 38 | if (name == null) throw new ArgumentNullException("name cannot be null."); 39 | Name = name; 40 | } 41 | 42 | override public String ToString () { 43 | return Name; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/AttachmentLoader.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public interface AttachmentLoader { 35 | /// May be null to not load any attachment. 36 | RegionAttachment NewRegionAttachment (Skin skin, String name, String path); 37 | 38 | /// May be null to not load any attachment. 39 | MeshAttachment NewMeshAttachment (Skin skin, String name, String path); 40 | 41 | /// May be null to not load any attachment. 42 | SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path); 43 | 44 | /// May be null to not load any attachment. 45 | BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/AttachmentType.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | namespace Spine { 32 | public enum AttachmentType { 33 | region, boundingbox, mesh, skinnedmesh 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/BoundingBoxAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | /// Attachment that has a polygon for bounds checking. 35 | public class BoundingBoxAttachment : Attachment { 36 | internal float[] vertices; 37 | 38 | public float[] Vertices { get { return vertices; } set { vertices = value; } } 39 | 40 | public BoundingBoxAttachment (string name) 41 | : base(name) { 42 | } 43 | 44 | /// Must have at least the same length as this attachment's vertices. 45 | public void ComputeWorldVertices (Bone bone, float[] worldVertices) { 46 | float x = bone.skeleton.x + bone.worldX, y = bone.skeleton.y + bone.worldY; 47 | float m00 = bone.m00; 48 | float m01 = bone.m01; 49 | float m10 = bone.m10; 50 | float m11 = bone.m11; 51 | float[] vertices = this.vertices; 52 | for (int i = 0, n = vertices.Length; i < n; i += 2) { 53 | float px = vertices[i]; 54 | float py = vertices[i + 1]; 55 | worldVertices[i] = px * m00 + py * m01 + x; 56 | worldVertices[i + 1] = px * m10 + py * m11 + y; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/MeshAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | /// Attachment that displays a texture region. 35 | public class MeshAttachment : Attachment { 36 | internal float[] vertices, uvs, regionUVs; 37 | internal int[] triangles; 38 | internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; 39 | internal float r = 1, g = 1, b = 1, a = 1; 40 | 41 | public int HullLength { get; set; } 42 | public float[] Vertices { get { return vertices; } set { vertices = value; } } 43 | public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } 44 | public float[] UVs { get { return uvs; } set { uvs = value; } } 45 | public int[] Triangles { get { return triangles; } set { triangles = value; } } 46 | 47 | public float R { get { return r; } set { r = value; } } 48 | public float G { get { return g; } set { g = value; } } 49 | public float B { get { return b; } set { b = value; } } 50 | public float A { get { return a; } set { a = value; } } 51 | 52 | public String Path { get; set; } 53 | public Object RendererObject { get; set; } 54 | public float RegionU { get; set; } 55 | public float RegionV { get; set; } 56 | public float RegionU2 { get; set; } 57 | public float RegionV2 { get; set; } 58 | public bool RegionRotate { get; set; } 59 | public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } 60 | public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. 61 | public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } 62 | public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. 63 | public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } 64 | public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. 65 | 66 | // Nonessential. 67 | //public int[] Edges { get; set; } //HuaHua Delete nonessential data 68 | //public float Width { get; set; } //HuaHua Delete nonessential data 69 | //public float Height { get; set; } //HuaHua Delete nonessential data 70 | 71 | public MeshAttachment (string name) 72 | : base(name) { 73 | } 74 | 75 | public void UpdateUVs () { 76 | float u = RegionU, v = RegionV, width = RegionU2 - RegionU, height = RegionV2 - RegionV; 77 | float[] regionUVs = this.regionUVs; 78 | if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; 79 | float[] uvs = this.uvs; 80 | if (RegionRotate) { 81 | for (int i = 0, n = uvs.Length; i < n; i += 2) { 82 | uvs[i] = u + regionUVs[i + 1] * width; 83 | uvs[i + 1] = v + height - regionUVs[i] * height; 84 | } 85 | } else { 86 | for (int i = 0, n = uvs.Length; i < n; i += 2) { 87 | uvs[i] = u + regionUVs[i] * width; 88 | uvs[i + 1] = v + regionUVs[i + 1] * height; 89 | } 90 | } 91 | } 92 | 93 | public void ComputeWorldVertices (Slot slot, float[] worldVertices) { 94 | Bone bone = slot.bone; 95 | float x = bone.skeleton.x + bone.worldX, y = bone.skeleton.y + bone.worldY; 96 | float m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; 97 | float[] vertices = this.vertices; 98 | int verticesCount = vertices.Length; 99 | if (slot.attachmentVerticesCount == verticesCount) vertices = slot.AttachmentVertices; 100 | for (int i = 0; i < verticesCount; i += 2) { 101 | float vx = vertices[i]; 102 | float vy = vertices[i + 1]; 103 | worldVertices[i] = vx * m00 + vy * m01 + x; 104 | worldVertices[i + 1] = vx * m10 + vy * m11 + y; 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/RegionAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | /// Attachment that displays a texture region. 35 | public class RegionAttachment : Attachment { 36 | public const int X1 = 0; 37 | public const int Y1 = 1; 38 | public const int X2 = 2; 39 | public const int Y2 = 3; 40 | public const int X3 = 4; 41 | public const int Y3 = 5; 42 | public const int X4 = 6; 43 | public const int Y4 = 7; 44 | 45 | internal float x, y, rotation, scaleX = 1, scaleY = 1, width, height; 46 | internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; 47 | internal float[] offset = new float[8], uvs = new float[8]; 48 | internal float r = 1, g = 1, b = 1, a = 1; 49 | 50 | public float X { get { return x; } set { x = value; } } 51 | public float Y { get { return y; } set { y = value; } } 52 | public float Rotation { get { return rotation; } set { rotation = value; } } 53 | public float ScaleX { get { return scaleX; } set { scaleX = value; } } 54 | public float ScaleY { get { return scaleY; } set { scaleY = value; } } 55 | public float Width { get { return width; } set { width = value; } } 56 | public float Height { get { return height; } set { height = value; } } 57 | 58 | public float R { get { return r; } set { r = value; } } 59 | public float G { get { return g; } set { g = value; } } 60 | public float B { get { return b; } set { b = value; } } 61 | public float A { get { return a; } set { a = value; } } 62 | 63 | public String Path { get; set; } 64 | public Object RendererObject { get; set; } 65 | public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } 66 | public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. 67 | public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } 68 | public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. 69 | public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } 70 | public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. 71 | 72 | public float[] Offset { get { return offset; } } 73 | public float[] UVs { get { return uvs; } } 74 | 75 | public RegionAttachment (string name) 76 | : base(name) { 77 | } 78 | 79 | public void SetUVs (float u, float v, float u2, float v2, bool rotate) { 80 | float[] uvs = this.uvs; 81 | if (rotate) { 82 | uvs[X2] = u; 83 | uvs[Y2] = v2; 84 | uvs[X3] = u; 85 | uvs[Y3] = v; 86 | uvs[X4] = u2; 87 | uvs[Y4] = v; 88 | uvs[X1] = u2; 89 | uvs[Y1] = v2; 90 | } else { 91 | uvs[X1] = u; 92 | uvs[Y1] = v2; 93 | uvs[X2] = u; 94 | uvs[Y2] = v; 95 | uvs[X3] = u2; 96 | uvs[Y3] = v; 97 | uvs[X4] = u2; 98 | uvs[Y4] = v2; 99 | } 100 | } 101 | 102 | public void UpdateOffset () { 103 | float width = this.width; 104 | float height = this.height; 105 | float scaleX = this.scaleX; 106 | float scaleY = this.scaleY; 107 | float regionScaleX = width / regionOriginalWidth * scaleX; 108 | float regionScaleY = height / regionOriginalHeight * scaleY; 109 | float localX = -width / 2 * scaleX + regionOffsetX * regionScaleX; 110 | float localY = -height / 2 * scaleY + regionOffsetY * regionScaleY; 111 | float localX2 = localX + regionWidth * regionScaleX; 112 | float localY2 = localY + regionHeight * regionScaleY; 113 | float radians = rotation * (float)Math.PI / 180; 114 | float cos = (float)Math.Cos(radians); 115 | float sin = (float)Math.Sin(radians); 116 | float x = this.x; 117 | float y = this.y; 118 | float localXCos = localX * cos + x; 119 | float localXSin = localX * sin; 120 | float localYCos = localY * cos + y; 121 | float localYSin = localY * sin; 122 | float localX2Cos = localX2 * cos + x; 123 | float localX2Sin = localX2 * sin; 124 | float localY2Cos = localY2 * cos + y; 125 | float localY2Sin = localY2 * sin; 126 | float[] offset = this.offset; 127 | offset[X1] = localXCos - localYSin; 128 | offset[Y1] = localYCos + localXSin; 129 | offset[X2] = localXCos - localY2Sin; 130 | offset[Y2] = localY2Cos + localXSin; 131 | offset[X3] = localX2Cos - localY2Sin; 132 | offset[Y3] = localY2Cos + localX2Sin; 133 | offset[X4] = localX2Cos - localYSin; 134 | offset[Y4] = localYCos + localX2Sin; 135 | } 136 | 137 | public void ComputeWorldVertices (Bone bone, float[] worldVertices) { 138 | float x = bone.skeleton.x + bone.worldX, y = bone.skeleton.y + bone.worldY; 139 | float m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; 140 | float[] offset = this.offset; 141 | worldVertices[X1] = offset[X1] * m00 + offset[Y1] * m01 + x; 142 | worldVertices[Y1] = offset[X1] * m10 + offset[Y1] * m11 + y; 143 | worldVertices[X2] = offset[X2] * m00 + offset[Y2] * m01 + x; 144 | worldVertices[Y2] = offset[X2] * m10 + offset[Y2] * m11 + y; 145 | worldVertices[X3] = offset[X3] * m00 + offset[Y3] * m01 + x; 146 | worldVertices[Y3] = offset[X3] * m10 + offset[Y3] * m11 + y; 147 | worldVertices[X4] = offset[X4] * m00 + offset[Y4] * m01 + x; 148 | worldVertices[Y4] = offset[X4] * m10 + offset[Y4] * m11 + y; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/SkinnedMeshAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | /// Attachment that displays a texture region. 36 | public class SkinnedMeshAttachment : Attachment { 37 | internal int[] bones; 38 | internal float[] weights, uvs, regionUVs; 39 | internal int[] triangles; 40 | internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; 41 | internal float r = 1, g = 1, b = 1, a = 1; 42 | 43 | public int HullLength { get; set; } 44 | public int[] Bones { get { return bones; } set { bones = value; } } 45 | public float[] Weights { get { return weights; } set { weights = value; } } 46 | public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } 47 | public float[] UVs { get { return uvs; } set { uvs = value; } } 48 | public int[] Triangles { get { return triangles; } set { triangles = value; } } 49 | 50 | public float R { get { return r; } set { r = value; } } 51 | public float G { get { return g; } set { g = value; } } 52 | public float B { get { return b; } set { b = value; } } 53 | public float A { get { return a; } set { a = value; } } 54 | 55 | public String Path { get; set; } 56 | public Object RendererObject { get; set; } 57 | public float RegionU { get; set; } 58 | public float RegionV { get; set; } 59 | public float RegionU2 { get; set; } 60 | public float RegionV2 { get; set; } 61 | public bool RegionRotate { get; set; } 62 | public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } 63 | public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. 64 | public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } 65 | public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. 66 | public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } 67 | public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. 68 | 69 | // Nonessential. 70 | //public int[] Edges { get; set; } //HuaHua Delete nonessential data 71 | //public float Width { get; set; } //HuaHua Delete nonessential data 72 | //public float Height { get; set; } //HuaHua Delete nonessential data 73 | 74 | public SkinnedMeshAttachment (string name) 75 | : base(name) { 76 | } 77 | 78 | public void UpdateUVs () { 79 | float u = RegionU, v = RegionV, width = RegionU2 - RegionU, height = RegionV2 - RegionV; 80 | float[] regionUVs = this.regionUVs; 81 | if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; 82 | float[] uvs = this.uvs; 83 | if (RegionRotate) { 84 | for (int i = 0, n = uvs.Length; i < n; i += 2) { 85 | uvs[i] = u + regionUVs[i + 1] * width; 86 | uvs[i + 1] = v + height - regionUVs[i] * height; 87 | } 88 | } else { 89 | for (int i = 0, n = uvs.Length; i < n; i += 2) { 90 | uvs[i] = u + regionUVs[i] * width; 91 | uvs[i + 1] = v + regionUVs[i + 1] * height; 92 | } 93 | } 94 | } 95 | 96 | public void ComputeWorldVertices (Slot slot, float[] worldVertices) { 97 | Skeleton skeleton = slot.bone.skeleton; 98 | List skeletonBones = skeleton.bones; 99 | float x = skeleton.x, y = skeleton.y; 100 | float[] weights = this.weights; 101 | int[] bones = this.bones; 102 | if (slot.attachmentVerticesCount == 0) { 103 | for (int w = 0, v = 0, b = 0, n = bones.Length; v < n; w += 2) { 104 | float wx = 0, wy = 0; 105 | int nn = bones[v++] + v; 106 | for (; v < nn; v++, b += 3) { 107 | Bone bone = skeletonBones[bones[v]]; 108 | float vx = weights[b], vy = weights[b + 1], weight = weights[b + 2]; 109 | wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; 110 | wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; 111 | } 112 | worldVertices[w] = wx + x; 113 | worldVertices[w + 1] = wy + y; 114 | } 115 | } else { 116 | float[] ffd = slot.AttachmentVertices; 117 | for (int w = 0, v = 0, b = 0, f = 0, n = bones.Length; v < n; w += 2) { 118 | float wx = 0, wy = 0; 119 | int nn = bones[v++] + v; 120 | for (; v < nn; v++, b += 3, f += 2) { 121 | Bone bone = skeletonBones[bones[v]]; 122 | float vx = weights[b] + ffd[f], vy = weights[b + 1] + ffd[f + 1], weight = weights[b + 2]; 123 | wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; 124 | wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; 125 | } 126 | worldVertices[w] = wx + x; 127 | worldVertices[w + 1] = wy + y; 128 | } 129 | } 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /spine-csharp/src/Bone.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class Bone{ 36 | static public bool yDown; 37 | 38 | internal BoneData data; 39 | internal Skeleton skeleton; 40 | internal Bone parent; 41 | internal List children = new List(); 42 | internal float x, y, rotation, rotationIK, scaleX, scaleY; 43 | internal bool flipX, flipY; 44 | internal float m00, m01, m10, m11; 45 | internal float worldX, worldY, worldRotation, worldScaleX, worldScaleY; 46 | internal bool worldFlipX, worldFlipY; 47 | 48 | public BoneData Data { get { return data; } } 49 | public Skeleton Skeleton { get { return skeleton; } } 50 | public Bone Parent { get { return parent; } } 51 | public List Children { get { return children; } } 52 | public float X { get { return x; } set { x = value; } } 53 | public float Y { get { return y; } set { y = value; } } 54 | /// The forward kinetics rotation. 55 | public float Rotation { get { return rotation; } set { rotation = value; } } 56 | /// The inverse kinetics rotation, as calculated by any IK constraints. 57 | public float RotationIK { get { return rotationIK; } set { rotationIK = value; } } 58 | public float ScaleX { get { return scaleX; } set { scaleX = value; } } 59 | public float ScaleY { get { return scaleY; } set { scaleY = value; } } 60 | public bool FlipX { get { return flipX; } set { flipX = value; } } 61 | public bool FlipY { get { return flipY; } set { flipY = value; } } 62 | 63 | public float M00 { get { return m00; } } 64 | public float M01 { get { return m01; } } 65 | public float M10 { get { return m10; } } 66 | public float M11 { get { return m11; } } 67 | public float WorldX { get { return worldX; } } 68 | public float WorldY { get { return worldY; } } 69 | public float WorldRotation { get { return worldRotation; } } 70 | public float WorldScaleX { get { return worldScaleX; } } 71 | public float WorldScaleY { get { return worldScaleY; } } 72 | public bool WorldFlipX { get { return worldFlipX; } set { worldFlipX = value; } } 73 | public bool WorldFlipY { get { return worldFlipY; } set { worldFlipY = value; } } 74 | 75 | /// May be null. 76 | public Bone (BoneData data, Skeleton skeleton, Bone parent) { 77 | if (data == null) throw new ArgumentNullException("data cannot be null."); 78 | if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null."); 79 | this.data = data; 80 | this.skeleton = skeleton; 81 | this.parent = parent; 82 | SetToSetupPose(); 83 | } 84 | 85 | /// Computes the world SRT using the parent bone and the local SRT. 86 | public void UpdateWorldTransform () { 87 | Bone parent = this.parent; 88 | float x = this.x, y = this.y; 89 | if (parent != null) { 90 | worldX = x * parent.m00 + y * parent.m01 + parent.worldX; 91 | worldY = x * parent.m10 + y * parent.m11 + parent.worldY; 92 | if (data.inheritScale) { 93 | worldScaleX = parent.worldScaleX * scaleX; 94 | worldScaleY = parent.worldScaleY * scaleY; 95 | } else { 96 | worldScaleX = scaleX; 97 | worldScaleY = scaleY; 98 | } 99 | worldRotation = data.inheritRotation ? parent.worldRotation + rotationIK : rotationIK; 100 | worldFlipX = parent.worldFlipX != flipX; 101 | worldFlipY = parent.worldFlipY != flipY; 102 | } else { 103 | Skeleton skeleton = this.skeleton; 104 | bool skeletonFlipX = skeleton.flipX, skeletonFlipY = skeleton.flipY; 105 | worldX = skeletonFlipX ? -x : x; 106 | worldY = skeletonFlipY != yDown ? -y : y; 107 | worldScaleX = scaleX; 108 | worldScaleY = scaleY; 109 | worldRotation = rotationIK; 110 | worldFlipX = skeletonFlipX != flipX; 111 | worldFlipY = skeletonFlipY != flipY; 112 | } 113 | float radians = worldRotation * (float)Math.PI / 180; 114 | float cos = (float)Math.Cos(radians); 115 | float sin = (float)Math.Sin(radians); 116 | if (worldFlipX) { 117 | m00 = -cos * worldScaleX; 118 | m01 = sin * worldScaleY; 119 | } else { 120 | m00 = cos * worldScaleX; 121 | m01 = -sin * worldScaleY; 122 | } 123 | if (worldFlipY != yDown) { 124 | m10 = -sin * worldScaleX; 125 | m11 = -cos * worldScaleY; 126 | } else { 127 | m10 = sin * worldScaleX; 128 | m11 = cos * worldScaleY; 129 | } 130 | } 131 | 132 | public void SetToSetupPose () { 133 | BoneData data = this.data; 134 | x = data.x; 135 | y = data.y; 136 | rotation = data.rotation; 137 | rotationIK = rotation; 138 | scaleX = data.scaleX; 139 | scaleY = data.scaleY; 140 | flipX = data.flipX; 141 | flipY = data.flipY; 142 | } 143 | 144 | public void worldToLocal (float worldX, float worldY, out float localX, out float localY) { 145 | float dx = worldX - this.worldX, dy = worldY - this.worldY; 146 | float m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11; 147 | if (worldFlipX != (worldFlipY != yDown)) { 148 | m00 = -m00; 149 | m11 = -m11; 150 | } 151 | float invDet = 1 / (m00 * m11 - m01 * m10); 152 | localX = (dx * m00 * invDet - dy * m01 * invDet); 153 | localY = (dy * m11 * invDet - dx * m10 * invDet); 154 | } 155 | 156 | public void localToWorld (float localX, float localY, out float worldX, out float worldY) { 157 | worldX = localX * m00 + localY * m01 + this.worldX; 158 | worldY = localX * m10 + localY * m11 + this.worldY; 159 | } 160 | 161 | override public String ToString () { 162 | return data.name; 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /spine-csharp/src/BoneData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class BoneData { 35 | internal BoneData parent; 36 | internal String name; 37 | internal float length, x, y, rotation, scaleX = 1, scaleY = 1; 38 | internal bool flipX, flipY; 39 | internal bool inheritScale = true, inheritRotation = true; 40 | 41 | /// May be null. 42 | public BoneData Parent { get { return parent; } } 43 | public String Name { get { return name; } } 44 | public float Length { get { return length; } set { length = value; } } 45 | public float X { get { return x; } set { x = value; } } 46 | public float Y { get { return y; } set { y = value; } } 47 | public float Rotation { get { return rotation; } set { rotation = value; } } 48 | public float ScaleX { get { return scaleX; } set { scaleX = value; } } 49 | public float ScaleY { get { return scaleY; } set { scaleY = value; } } 50 | public bool FlipX { get { return flipX; } set { flipX = value; } } 51 | public bool FlipY { get { return flipY; } set { flipY = value; } } 52 | public bool InheritScale { get { return inheritScale; } set { inheritScale = value; } } 53 | public bool InheritRotation { get { return inheritRotation; } set { inheritRotation = value; } } 54 | 55 | /// May be null. 56 | public BoneData (String name, BoneData parent) { 57 | if (name == null) throw new ArgumentNullException("name cannot be null."); 58 | this.name = name; 59 | this.parent = parent; 60 | } 61 | 62 | override public String ToString () { 63 | return name; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /spine-csharp/src/Event.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class Event { 35 | public EventData Data { get; private set; } 36 | public int Int { get; set; } 37 | public float Float { get; set; } 38 | public String String { get; set; } 39 | 40 | public Event (EventData data) { 41 | Data = data; 42 | } 43 | 44 | override public String ToString () { 45 | return Data.Name; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /spine-csharp/src/EventData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class EventData { 35 | internal String name; 36 | 37 | public String Name { get { return name; } } 38 | public int Int { get; set; } 39 | public float Float { get; set; } 40 | public String String { get; set; } 41 | 42 | public EventData (String name) { 43 | if (name == null) throw new ArgumentNullException("name cannot be null."); 44 | this.name = name; 45 | } 46 | 47 | override public String ToString () { 48 | return Name; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /spine-csharp/src/IkConstraint.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class IkConstraint { 36 | private const float radDeg = 180 / (float)Math.PI; 37 | 38 | internal IkConstraintData data; 39 | internal List bones = new List(); 40 | internal Bone target; 41 | internal int bendDirection; 42 | internal float mix; 43 | 44 | public IkConstraintData Data { get { return data; } } 45 | public List Bones { get { return bones; } } 46 | public Bone Target { get { return target; } set { target = value; } } 47 | public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } 48 | public float Mix { get { return mix; } set { mix = value; } } 49 | 50 | public IkConstraint (IkConstraintData data, Skeleton skeleton) { 51 | if (data == null) throw new ArgumentNullException("data cannot be null."); 52 | if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null."); 53 | this.data = data; 54 | mix = data.mix; 55 | bendDirection = data.bendDirection; 56 | 57 | bones = new List(data.bones.Count); 58 | foreach (BoneData boneData in data.bones) 59 | bones.Add(skeleton.FindBone(boneData.name)); 60 | target = skeleton.FindBone(data.target.name); 61 | } 62 | 63 | public void apply () { 64 | Bone target = this.target; 65 | List bones = this.bones; 66 | switch (bones.Count) { 67 | case 1: 68 | apply(bones[0], target.worldX, target.worldY, mix); 69 | break; 70 | case 2: 71 | apply(bones[0], bones[1], target.worldX, target.worldY, bendDirection, mix); 72 | break; 73 | } 74 | } 75 | 76 | override public String ToString () { 77 | return data.name; 78 | } 79 | 80 | /// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified 81 | /// in the world coordinate system. 82 | static public void apply (Bone bone, float targetX, float targetY, float alpha) { 83 | float parentRotation = (!bone.data.inheritRotation || bone.parent == null) ? 0 : bone.parent.worldRotation; 84 | float rotation = bone.rotation; 85 | float rotationIK = (float)Math.Atan2(targetY - bone.worldY, targetX - bone.worldX) * radDeg; 86 | if (bone.worldFlipX != (bone.worldFlipY != Bone.yDown)) rotationIK = -rotationIK; 87 | rotationIK -= parentRotation; 88 | bone.rotationIK = rotation + (rotationIK - rotation) * alpha; 89 | } 90 | 91 | /// Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as 92 | /// possible. The target is specified in the world coordinate system. 93 | /// Any descendant bone of the parent. 94 | static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDirection, float alpha) { 95 | float childRotation = child.rotation, parentRotation = parent.rotation; 96 | if (alpha == 0) { 97 | child.rotationIK = childRotation; 98 | parent.rotationIK = parentRotation; 99 | return; 100 | } 101 | float positionX, positionY; 102 | Bone parentParent = parent.parent; 103 | if (parentParent != null) { 104 | parentParent.worldToLocal(targetX, targetY, out positionX, out positionY); 105 | targetX = (positionX - parent.x) * parentParent.worldScaleX; 106 | targetY = (positionY - parent.y) * parentParent.worldScaleY; 107 | } else { 108 | targetX -= parent.x; 109 | targetY -= parent.y; 110 | } 111 | if (child.parent == parent) { 112 | positionX = child.x; 113 | positionY = child.y; 114 | } else { 115 | child.parent.localToWorld(child.x, child.y, out positionX, out positionY); 116 | parent.worldToLocal(positionX, positionY, out positionX, out positionY); 117 | } 118 | float childX = positionX * parent.worldScaleX, childY = positionY * parent.worldScaleY; 119 | float offset = (float)Math.Atan2(childY, childX); 120 | float len1 = (float)Math.Sqrt(childX * childX + childY * childY), len2 = child.data.length * child.worldScaleX; 121 | // Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/ 122 | float cosDenom = 2 * len1 * len2; 123 | if (cosDenom < 0.0001f) { 124 | child.rotationIK = childRotation + ((float)Math.Atan2(targetY, targetX) * radDeg - parentRotation - childRotation) 125 | * alpha; 126 | return; 127 | } 128 | float cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom; 129 | if (cos < -1) 130 | cos = -1; 131 | else if (cos > 1) 132 | cos = 1; 133 | float childAngle = (float)Math.Acos(cos) * bendDirection; 134 | float adjacent = len1 + len2 * cos, opposite = len2 * (float)Math.Sin(childAngle); 135 | float parentAngle = (float)Math.Atan2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite); 136 | float rotation = (parentAngle - offset) * radDeg - parentRotation; 137 | if (rotation > 180) 138 | rotation -= 360; 139 | else if (rotation < -180) // 140 | rotation += 360; 141 | parent.rotationIK = parentRotation + rotation * alpha; 142 | rotation = (childAngle + offset) * radDeg - childRotation; 143 | if (rotation > 180) 144 | rotation -= 360; 145 | else if (rotation < -180) // 146 | rotation += 360; 147 | child.rotationIK = childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha; 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /spine-csharp/src/IkConstraintData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class IkConstraintData { 36 | internal String name; 37 | internal List bones = new List(); 38 | internal BoneData target; 39 | internal int bendDirection = 1; 40 | internal float mix = 1; 41 | 42 | public String Name { get { return name; } } 43 | public List Bones { get { return bones; } } 44 | public BoneData Target { get { return target; } set { target = value; } } 45 | public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } 46 | public float Mix { get { return mix; } set { mix = value; } } 47 | 48 | public IkConstraintData (String name) { 49 | if (name == null) throw new ArgumentNullException("name cannot be null."); 50 | this.name = name; 51 | } 52 | 53 | override public String ToString () { 54 | return name; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /spine-csharp/src/SkeletonBounds.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class SkeletonBounds { 36 | private List polygonPool = new List(); 37 | private float minX, minY, maxX, maxY; 38 | 39 | public List BoundingBoxes { get; private set; } 40 | public List Polygons { get; private set; } 41 | public float MinX { get { return minX; } set { minX = value; } } 42 | public float MinY { get { return minY; } set { minY = value; } } 43 | public float MaxX { get { return maxX; } set { maxX = value; } } 44 | public float MaxY { get { return maxY; } set { maxY = value; } } 45 | public float Width { get { return maxX - minX; } } 46 | public float Height { get { return maxY - minY; } } 47 | 48 | public SkeletonBounds () { 49 | BoundingBoxes = new List(); 50 | Polygons = new List(); 51 | } 52 | 53 | public void Update (Skeleton skeleton, bool updateAabb) { 54 | List boundingBoxes = BoundingBoxes; 55 | List polygons = Polygons; 56 | List slots = skeleton.slots; 57 | int slotCount = slots.Count; 58 | 59 | boundingBoxes.Clear(); 60 | foreach (Polygon polygon in polygons) 61 | polygonPool.Add(polygon); 62 | polygons.Clear(); 63 | 64 | for (int i = 0; i < slotCount; i++) { 65 | Slot slot = slots[i]; 66 | BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment; 67 | if (boundingBox == null) continue; 68 | boundingBoxes.Add(boundingBox); 69 | 70 | Polygon polygon = null; 71 | int poolCount = polygonPool.Count; 72 | if (poolCount > 0) { 73 | polygon = polygonPool[poolCount - 1]; 74 | polygonPool.RemoveAt(poolCount - 1); 75 | } else 76 | polygon = new Polygon(); 77 | polygons.Add(polygon); 78 | 79 | int count = boundingBox.Vertices.Length; 80 | polygon.Count = count; 81 | if (polygon.Vertices.Length < count) polygon.Vertices = new float[count]; 82 | boundingBox.ComputeWorldVertices(slot.bone, polygon.Vertices); 83 | } 84 | 85 | if (updateAabb) aabbCompute(); 86 | } 87 | 88 | private void aabbCompute () { 89 | float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; 90 | List polygons = Polygons; 91 | for (int i = 0, n = polygons.Count; i < n; i++) { 92 | Polygon polygon = polygons[i]; 93 | float[] vertices = polygon.Vertices; 94 | for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) { 95 | float x = vertices[ii]; 96 | float y = vertices[ii + 1]; 97 | minX = Math.Min(minX, x); 98 | minY = Math.Min(minY, y); 99 | maxX = Math.Max(maxX, x); 100 | maxY = Math.Max(maxY, y); 101 | } 102 | } 103 | this.minX = minX; 104 | this.minY = minY; 105 | this.maxX = maxX; 106 | this.maxY = maxY; 107 | } 108 | 109 | 110 | /// Returns true if the axis aligned bounding box contains the point. 111 | public bool AabbContainsPoint (float x, float y) { 112 | return x >= minX && x <= maxX && y >= minY && y <= maxY; 113 | } 114 | 115 | /// Returns true if the axis aligned bounding box intersects the line segment. 116 | public bool AabbIntersectsSegment (float x1, float y1, float x2, float y2) { 117 | float minX = this.minX; 118 | float minY = this.minY; 119 | float maxX = this.maxX; 120 | float maxY = this.maxY; 121 | if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) 122 | return false; 123 | float m = (y2 - y1) / (x2 - x1); 124 | float y = m * (minX - x1) + y1; 125 | if (y > minY && y < maxY) return true; 126 | y = m * (maxX - x1) + y1; 127 | if (y > minY && y < maxY) return true; 128 | float x = (minY - y1) / m + x1; 129 | if (x > minX && x < maxX) return true; 130 | x = (maxY - y1) / m + x1; 131 | if (x > minX && x < maxX) return true; 132 | return false; 133 | } 134 | 135 | /// Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. 136 | public bool AabbIntersectsSkeleton (SkeletonBounds bounds) { 137 | return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; 138 | } 139 | 140 | /// Returns true if the polygon contains the point. 141 | public bool ContainsPoint (Polygon polygon, float x, float y) { 142 | float[] vertices = polygon.Vertices; 143 | int nn = polygon.Count; 144 | 145 | int prevIndex = nn - 2; 146 | bool inside = false; 147 | for (int ii = 0; ii < nn; ii += 2) { 148 | float vertexY = vertices[ii + 1]; 149 | float prevY = vertices[prevIndex + 1]; 150 | if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { 151 | float vertexX = vertices[ii]; 152 | if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; 153 | } 154 | prevIndex = ii; 155 | } 156 | return inside; 157 | } 158 | 159 | /// Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more 160 | /// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. 161 | public BoundingBoxAttachment ContainsPoint (float x, float y) { 162 | List polygons = Polygons; 163 | for (int i = 0, n = polygons.Count; i < n; i++) 164 | if (ContainsPoint(polygons[i], x, y)) return BoundingBoxes[i]; 165 | return null; 166 | } 167 | 168 | /// Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually 169 | /// more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. 170 | public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) { 171 | List polygons = Polygons; 172 | for (int i = 0, n = polygons.Count; i < n; i++) 173 | if (IntersectsSegment(polygons[i], x1, y1, x2, y2)) return BoundingBoxes[i]; 174 | return null; 175 | } 176 | 177 | /// Returns true if the polygon contains the line segment. 178 | public bool IntersectsSegment (Polygon polygon, float x1, float y1, float x2, float y2) { 179 | float[] vertices = polygon.Vertices; 180 | int nn = polygon.Count; 181 | 182 | float width12 = x1 - x2, height12 = y1 - y2; 183 | float det1 = x1 * y2 - y1 * x2; 184 | float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; 185 | for (int ii = 0; ii < nn; ii += 2) { 186 | float x4 = vertices[ii], y4 = vertices[ii + 1]; 187 | float det2 = x3 * y4 - y3 * x4; 188 | float width34 = x3 - x4, height34 = y3 - y4; 189 | float det3 = width12 * height34 - height12 * width34; 190 | float x = (det1 * width34 - width12 * det2) / det3; 191 | if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { 192 | float y = (det1 * height34 - height12 * det2) / det3; 193 | if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; 194 | } 195 | x3 = x4; 196 | y3 = y4; 197 | } 198 | return false; 199 | } 200 | 201 | public Polygon getPolygon (BoundingBoxAttachment attachment) { 202 | int index = BoundingBoxes.IndexOf(attachment); 203 | return index == -1 ? null : Polygons[index]; 204 | } 205 | } 206 | 207 | public class Polygon { 208 | public float[] Vertices { get; set; } 209 | public int Count { get; set; } 210 | 211 | public Polygon () { 212 | Vertices = new float[16]; 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /spine-csharp/src/SkeletonData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class SkeletonData { 36 | internal String name; 37 | internal List bones = new List(); 38 | internal List slots = new List(); 39 | internal List skins = new List(); 40 | internal Skin defaultSkin; 41 | internal List events = new List(); 42 | internal List animations = new List(); 43 | internal List ikConstraints = new List(); 44 | internal float width, height; 45 | internal String version, hash;//, imagesPath; //HuaHua Delete nonessential data 46 | 47 | public String Name { get { return name; } set { name = value; } } 48 | public List Bones { get { return bones; } } // Ordered parents first. 49 | public List Slots { get { return slots; } } // Setup pose draw order. 50 | public List Skins { get { return skins; } set { skins = value; } } 51 | /// May be null. 52 | public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } } 53 | public List Events { get { return events; } set { events = value; } } 54 | public List Animations { get { return animations; } set { animations = value; } } 55 | public List IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } 56 | public float Width { get { return width; } set { width = value; } } 57 | public float Height { get { return height; } set { height = value; } } 58 | /// The Spine version used to export this data. 59 | public String Version { get { return version; } set { version = value; } } 60 | public String Hash { get { return hash; } set { hash = value; } } 61 | 62 | // --- Bones. 63 | 64 | /// May be null. 65 | public BoneData FindBone (String boneName) { 66 | if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); 67 | List bones = this.bones; 68 | for (int i = 0, n = bones.Count; i < n; i++) { 69 | BoneData bone = bones[i]; 70 | if (bone.name == boneName) return bone; 71 | } 72 | return null; 73 | } 74 | 75 | /// -1 if the bone was not found. 76 | public int FindBoneIndex (String boneName) { 77 | if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); 78 | List bones = this.bones; 79 | for (int i = 0, n = bones.Count; i < n; i++) 80 | if (bones[i].name == boneName) return i; 81 | return -1; 82 | } 83 | 84 | // --- Slots. 85 | 86 | /// May be null. 87 | public SlotData FindSlot (String slotName) { 88 | if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); 89 | List slots = this.slots; 90 | for (int i = 0, n = slots.Count; i < n; i++) { 91 | SlotData slot = slots[i]; 92 | if (slot.name == slotName) return slot; 93 | } 94 | return null; 95 | } 96 | 97 | /// -1 if the bone was not found. 98 | public int FindSlotIndex (String slotName) { 99 | if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); 100 | List slots = this.slots; 101 | for (int i = 0, n = slots.Count; i < n; i++) 102 | if (slots[i].name == slotName) return i; 103 | return -1; 104 | } 105 | 106 | // --- Skins. 107 | 108 | /// May be null. 109 | public Skin FindSkin (String skinName) { 110 | if (skinName == null) throw new ArgumentNullException("skinName cannot be null."); 111 | foreach (Skin skin in skins) 112 | if (skin.name == skinName) return skin; 113 | return null; 114 | } 115 | 116 | // --- Events. 117 | 118 | /// May be null. 119 | public EventData FindEvent (String eventDataName) { 120 | if (eventDataName == null) throw new ArgumentNullException("eventDataName cannot be null."); 121 | foreach (EventData eventData in events) 122 | if (eventData.name == eventDataName) return eventData; 123 | return null; 124 | } 125 | 126 | // --- Animations. 127 | 128 | /// May be null. 129 | public Animation FindAnimation (String animationName) { 130 | if (animationName == null) throw new ArgumentNullException("animationName cannot be null."); 131 | List animations = this.animations; 132 | for (int i = 0, n = animations.Count; i < n; i++) { 133 | Animation animation = animations[i]; 134 | if (animation.name == animationName) return animation; 135 | } 136 | return null; 137 | } 138 | 139 | public Animation FindAnimationByIndex (int animationIndex) { 140 | List animations = this.animations; 141 | if (animationIndex >= animations.Count) 142 | return null; 143 | return animations[animationIndex]; 144 | } 145 | 146 | // --- IK constraints. 147 | 148 | /// May be null. 149 | public IkConstraintData FindIkConstraint (String ikConstraintName) { 150 | if (ikConstraintName == null) throw new ArgumentNullException("ikConstraintName cannot be null."); 151 | List ikConstraints = this.ikConstraints; 152 | for (int i = 0, n = ikConstraints.Count; i < n; i++) { 153 | IkConstraintData ikConstraint = ikConstraints[i]; 154 | if (ikConstraint.name == ikConstraintName) return ikConstraint; 155 | } 156 | return null; 157 | } 158 | 159 | public string GetAttachName(Attachment attachment) 160 | { 161 | for (int si = 0; si < skins.Count; ++si) 162 | { 163 | var skin = skins[si]; 164 | foreach (var entry in skin.Attachments) 165 | { 166 | foreach (var each in entry.Value) 167 | { 168 | if (attachment == each.Value) 169 | { 170 | return each.Key; 171 | } 172 | } 173 | } 174 | } 175 | return null; 176 | } 177 | 178 | public int GetSkinIndex(Attachment attachment) 179 | { 180 | for (int si = 0; si < skins.Count; ++si) 181 | { 182 | var skin = skins[si]; 183 | foreach (var entry in skin.Attachments) 184 | { 185 | foreach (var each in entry.Value) 186 | { 187 | if (attachment == each.Value) 188 | { 189 | return si; 190 | } 191 | } 192 | } 193 | } 194 | 195 | return -1; 196 | } 197 | 198 | // --- 199 | 200 | override public String ToString () { 201 | return name ?? base.ToString(); 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /spine-csharp/src/Skin.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | /// Stores attachments by slot index and attachment name. 36 | public class Skin { 37 | internal String name; 38 | 39 | // HuaHua. quickly find 40 | private Dictionary> attachments = 41 | new Dictionary>(); 42 | 43 | #if UNITY_EDITOR 44 | //HuaHua 45 | internal Dictionary> Attachments 46 | { 47 | get 48 | { 49 | return attachments; 50 | } 51 | } 52 | #endif 53 | 54 | public String Name { get { return name; } } 55 | 56 | public Skin (String name) { 57 | if (name == null) throw new ArgumentNullException("name cannot be null."); 58 | this.name = name; 59 | } 60 | 61 | public void AddAttachment (int slotIndex, String name, Attachment attachment) { 62 | if (attachment == null) throw new ArgumentNullException("attachment cannot be null."); 63 | 64 | if (!attachments.TryGetValue(slotIndex, out Dictionary ats)) 65 | { 66 | ats = new Dictionary(); 67 | attachments.Add(slotIndex, ats); 68 | } 69 | ats[name] = attachment; 70 | } 71 | 72 | /// May be null. 73 | public Attachment GetAttachment (int slotIndex, String name) { 74 | if (!attachments.TryGetValue(slotIndex, out Dictionary ats)) 75 | { 76 | return null; 77 | } 78 | 79 | ats.TryGetValue(name, out Attachment attachment); 80 | return attachment; 81 | } 82 | 83 | public void RemoveAttachment(int slotIndex, string name) { 84 | if (attachments.TryGetValue(slotIndex, out Dictionary ats)) 85 | { 86 | ats.Remove(name); 87 | if (ats.Count == 0) 88 | { 89 | attachments.Remove(slotIndex); 90 | } 91 | } 92 | } 93 | 94 | public void RemoveAttachmentsForSlot(int slotIndex) 95 | { 96 | var names = new List(); 97 | FindNamesForSlot(slotIndex, names); 98 | foreach (var name in names) 99 | { 100 | RemoveAttachment(slotIndex, name); 101 | } 102 | } 103 | 104 | public void FindNamesForSlot (int slotIndex, List names) { 105 | if (names == null) throw new ArgumentNullException("names cannot be null."); 106 | if (attachments.TryGetValue(slotIndex, out Dictionary ats)) 107 | { 108 | foreach(var each in ats) 109 | { 110 | names.Add(each.Key); 111 | } 112 | } 113 | } 114 | 115 | public void FindAttachmentsForSlot (int slotIndex, List attachments) { 116 | if (attachments == null) throw new ArgumentNullException("attachments cannot be null."); 117 | if (this.attachments.TryGetValue(slotIndex, out Dictionary ats)) 118 | { 119 | foreach (var each in ats) 120 | { 121 | attachments.Add(each.Value); 122 | } 123 | } 124 | } 125 | 126 | override public String ToString () { 127 | return name; 128 | } 129 | 130 | ///Adds all attachments from the specified skin to this skin. 131 | public void CopySkin(Skin skin) 132 | { 133 | foreach (var entry in skin.attachments) 134 | { 135 | int slotIndex = entry.Key; 136 | foreach(var each in entry.Value) 137 | { 138 | AddAttachment(slotIndex, each.Key, each.Value); 139 | } 140 | } 141 | } 142 | 143 | public void DetachSkin(Skin skin) 144 | { 145 | foreach (var entry in skin.attachments) 146 | { 147 | int slotIndex = entry.Key; 148 | foreach (var each in entry.Value) 149 | { 150 | RemoveAttachment(slotIndex, each.Key); 151 | } 152 | } 153 | } 154 | 155 | // Avoids boxing in the dictionary. 156 | private class AttachmentComparer : IEqualityComparer> { 157 | internal static readonly AttachmentComparer Instance = new AttachmentComparer(); 158 | 159 | bool IEqualityComparer>.Equals (KeyValuePair o1, KeyValuePair o2) { 160 | return o1.Key == o2.Key && o1.Value == o2.Value; 161 | } 162 | 163 | int IEqualityComparer>.GetHashCode (KeyValuePair o) { 164 | return o.Key; 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /spine-csharp/src/Slot.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class Slot { 35 | internal SlotData data; 36 | internal Bone bone; 37 | internal float r, g, b, a; 38 | internal Attachment attachment; 39 | internal float attachmentTime; 40 | internal float[] attachmentVertices = new float[0]; 41 | internal int attachmentVerticesCount; 42 | 43 | public SlotData Data { get { return data; } } 44 | public Bone Bone { get { return bone; } } 45 | public Skeleton Skeleton { get { return bone.skeleton; } } 46 | public float R { get { return r; } set { r = value; } } 47 | public float G { get { return g; } set { g = value; } } 48 | public float B { get { return b; } set { b = value; } } 49 | public float A { get { return a; } set { a = value; } } 50 | 51 | /// May be null. 52 | public Attachment Attachment { 53 | get { 54 | return attachment; 55 | } 56 | set { 57 | attachment = value; 58 | attachmentTime = bone.skeleton.time; 59 | attachmentVerticesCount = 0; 60 | } 61 | } 62 | 63 | public float AttachmentTime { 64 | get { 65 | return bone.skeleton.time - attachmentTime; 66 | } 67 | set { 68 | attachmentTime = bone.skeleton.time - value; 69 | } 70 | } 71 | 72 | public float[] AttachmentVertices { get { return attachmentVertices; } set { attachmentVertices = value; } } 73 | public int AttachmentVerticesCount { get { return attachmentVerticesCount; } set { attachmentVerticesCount = value; } } 74 | 75 | public Slot (SlotData data, Bone bone) { 76 | if (data == null) throw new ArgumentNullException("data cannot be null."); 77 | if (bone == null) throw new ArgumentNullException("bone cannot be null."); 78 | this.data = data; 79 | this.bone = bone; 80 | SetToSetupPose(); 81 | } 82 | 83 | internal void SetToSetupPose (int slotIndex) { 84 | r = data.r; 85 | g = data.g; 86 | b = data.b; 87 | a = data.a; 88 | Attachment = data.attachmentName == null ? null : bone.skeleton.GetAttachment(slotIndex, data.attachmentName); 89 | } 90 | 91 | public void SetToSetupPose () { 92 | SetToSetupPose(bone.skeleton.data.slots.IndexOf(data)); 93 | } 94 | 95 | override public String ToString () { 96 | return data.name; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /spine-csharp/src/SlotData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class SlotData { 35 | internal String name; 36 | internal BoneData boneData; 37 | internal float r = 1, g = 1, b = 1, a = 1; 38 | internal String attachmentName; 39 | internal bool additiveBlending; 40 | 41 | public String Name { get { return name; } } 42 | public BoneData BoneData { get { return boneData; } } 43 | public float R { get { return r; } set { r = value; } } 44 | public float G { get { return g; } set { g = value; } } 45 | public float B { get { return b; } set { b = value; } } 46 | public float A { get { return a; } set { a = value; } } 47 | /// May be null. 48 | public String AttachmentName { get { return attachmentName; } set { attachmentName = value; } } 49 | public bool AdditiveBlending { get { return additiveBlending; } set { additiveBlending = value; } } 50 | 51 | public SlotData (String name, BoneData boneData) { 52 | if (name == null) throw new ArgumentNullException("name cannot be null."); 53 | if (boneData == null) throw new ArgumentNullException("boneData cannot be null."); 54 | this.name = name; 55 | this.boneData = boneData; 56 | } 57 | 58 | override public String ToString () { 59 | return name; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /spine-unity/AtlasAsset.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.IO; 33 | using UnityEngine; 34 | using Spine; 35 | 36 | /// Loads and stores a Spine atlas and list of materials. 37 | public class AtlasAsset : ScriptableObject { 38 | public TextAsset atlasFile; 39 | public Material[] materials; 40 | private Atlas atlas; 41 | 42 | public void Reset () { 43 | atlas = null; 44 | } 45 | 46 | /// The atlas or null if it could not be loaded. 47 | public Atlas GetAtlas () { 48 | if (atlasFile == null) { 49 | Debug.LogError("Atlas file not set for atlas asset: " + name, this); 50 | Reset(); 51 | return null; 52 | } 53 | 54 | if (materials == null || materials.Length == 0) { 55 | Debug.LogError("Materials not set for atlas asset: " + name, this); 56 | Reset(); 57 | return null; 58 | } 59 | 60 | if (atlas != null) 61 | return atlas; 62 | 63 | try { 64 | atlas = new Atlas(new StringReader(atlasFile.text), "", new MaterialsTextureLoader(this)); 65 | atlas.FlipV(); 66 | return atlas; 67 | } catch (Exception ex) { 68 | Debug.LogError("Error reading atlas file for atlas asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this); 69 | return null; 70 | } 71 | } 72 | } 73 | 74 | public class MaterialsTextureLoader : TextureLoader { 75 | AtlasAsset atlasAsset; 76 | 77 | public MaterialsTextureLoader (AtlasAsset atlasAsset) { 78 | this.atlasAsset = atlasAsset; 79 | } 80 | 81 | public void Load (AtlasPage page, String path) { 82 | String name = Path.GetFileNameWithoutExtension(path); 83 | Material material = null; 84 | foreach (Material other in atlasAsset.materials) { 85 | if (other.mainTexture == null) { 86 | Debug.LogError("Material is missing texture: " + other.name, other); 87 | return; 88 | } 89 | if (other.mainTexture.name == name) { 90 | material = other; 91 | break; 92 | } 93 | } 94 | if (material == null) { 95 | Debug.LogError("Material with texture name \"" + name + "\" not found for atlas asset: " + atlasAsset.name, atlasAsset); 96 | return; 97 | } 98 | page.rendererObject = material; 99 | 100 | // Very old atlas files expected the texture's actual size to be used at runtime. 101 | if (page.width == 0 || page.height == 0) { 102 | page.width = material.mainTexture.width; 103 | page.height = material.mainTexture.height; 104 | } 105 | } 106 | 107 | public void Unload (object texture) { 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /spine-unity/AtlasRegionAttacher.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using Spine; 4 | 5 | 6 | public class AtlasRegionAttacher : MonoBehaviour { 7 | 8 | [System.Serializable] 9 | public class SlotRegionPair { 10 | [SpineSlot] 11 | public string slot; 12 | 13 | [SpineAtlasRegion] 14 | public string region; 15 | } 16 | 17 | public AtlasAsset atlasAsset; 18 | public SlotRegionPair[] attachments; 19 | 20 | Atlas atlas; 21 | 22 | void Awake() { 23 | GetComponent().OnReset += Apply; 24 | } 25 | 26 | 27 | void Apply(SkeletonRenderer skeletonRenderer) { 28 | atlas = atlasAsset.GetAtlas(); 29 | 30 | AtlasAttachmentLoader loader = new AtlasAttachmentLoader(atlas); 31 | 32 | float scaleMultiplier = skeletonRenderer.skeletonDataAsset.scale; 33 | 34 | var enumerator = attachments.GetEnumerator(); 35 | while (enumerator.MoveNext()) { 36 | var entry = (SlotRegionPair)enumerator.Current; 37 | var regionAttachment = loader.NewRegionAttachment(null, entry.region, entry.region); 38 | regionAttachment.Width = regionAttachment.RegionOriginalWidth * scaleMultiplier; 39 | regionAttachment.Height = regionAttachment.RegionOriginalHeight * scaleMultiplier; 40 | 41 | regionAttachment.SetColor(new Color(1, 1, 1, 1)); 42 | regionAttachment.UpdateOffset(); 43 | 44 | var slot = skeletonRenderer.skeleton.FindSlot(entry.slot); 45 | slot.Attachment = regionAttachment; 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /spine-unity/BoneFollower.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.IO; 33 | using System.Collections.Generic; 34 | using UnityEngine; 35 | using Spine; 36 | 37 | /// Sets a GameObject's transform to match a bone on a Spine skeleton. 38 | [ExecuteInEditMode] 39 | [AddComponentMenu("Spine/BoneFollower")] 40 | public class BoneFollower : MonoBehaviour { 41 | 42 | [System.NonSerialized] 43 | public bool 44 | valid; 45 | public SkeletonRenderer skeletonRenderer; 46 | public Bone bone; 47 | public bool followZPosition = true; 48 | public bool followBoneRotation = true; 49 | 50 | public SkeletonRenderer SkeletonRenderer { 51 | get { return skeletonRenderer; } 52 | set { 53 | skeletonRenderer = value; 54 | Reset(); 55 | } 56 | } 57 | 58 | 59 | /// If a bone isn't set, boneName is used to find the bone. 60 | public String boneName; 61 | public bool resetOnAwake = true; 62 | protected Transform cachedTransform; 63 | protected Transform skeletonTransform; 64 | 65 | public void HandleResetRenderer (SkeletonRenderer skeletonRenderer) { 66 | Reset(); 67 | } 68 | 69 | public void Reset () { 70 | bone = null; 71 | cachedTransform = transform; 72 | valid = skeletonRenderer != null && skeletonRenderer.valid; 73 | if (!valid) 74 | return; 75 | skeletonTransform = skeletonRenderer.transform; 76 | 77 | skeletonRenderer.OnReset -= HandleResetRenderer; 78 | skeletonRenderer.OnReset += HandleResetRenderer; 79 | 80 | if (Application.isEditor) 81 | DoUpdate(); 82 | } 83 | 84 | void OnDestroy () { 85 | //cleanup 86 | if (skeletonRenderer != null) 87 | skeletonRenderer.OnReset -= HandleResetRenderer; 88 | } 89 | 90 | public void Awake () { 91 | if (resetOnAwake) 92 | Reset(); 93 | } 94 | 95 | void LateUpdate () { 96 | DoUpdate(); 97 | } 98 | 99 | public void DoUpdate () { 100 | if (!valid) { 101 | Reset(); 102 | return; 103 | } 104 | 105 | if (bone == null) { 106 | if (boneName == null || boneName.Length == 0) 107 | return; 108 | bone = skeletonRenderer.skeleton.FindBone(boneName); 109 | if (bone == null) { 110 | Debug.LogError("Bone not found: " + boneName, this); 111 | return; 112 | } else { 113 | 114 | } 115 | } 116 | 117 | Spine.Skeleton skeleton = skeletonRenderer.skeleton; 118 | float flipRotation = (skeleton.flipX ^ skeleton.flipY) ? -1f : 1f; 119 | 120 | if (cachedTransform.parent == skeletonTransform) { 121 | cachedTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : cachedTransform.localPosition.z); 122 | 123 | if (followBoneRotation) { 124 | Vector3 rotation = cachedTransform.localRotation.eulerAngles; 125 | cachedTransform.localRotation = Quaternion.Euler(rotation.x, rotation.y, bone.worldRotation * flipRotation); 126 | } 127 | 128 | } else { 129 | Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY, 0f)); 130 | if (!followZPosition) 131 | targetWorldPosition.z = cachedTransform.position.z; 132 | 133 | cachedTransform.position = targetWorldPosition; 134 | 135 | if (followBoneRotation) { 136 | Vector3 rotation = skeletonTransform.rotation.eulerAngles; 137 | 138 | cachedTransform.rotation = Quaternion.Euler(rotation.x, rotation.y, skeletonTransform.rotation.eulerAngles.z + (bone.worldRotation * flipRotation)); 139 | } 140 | } 141 | 142 | } 143 | } -------------------------------------------------------------------------------- /spine-unity/CustomSkin.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using Spine; 4 | 5 | public class CustomSkin : MonoBehaviour { 6 | 7 | 8 | [System.Serializable] 9 | public class SkinPair { 10 | [SpineAttachment(currentSkinOnly: false, returnAttachmentPath: true, dataField: "skinSource")] 11 | public string sourceAttachment; 12 | [SpineSlot] 13 | public string targetSlot; 14 | [SpineAttachment(currentSkinOnly: true, placeholdersOnly: true)] 15 | public string targetAttachment; 16 | } 17 | 18 | public SkeletonDataAsset skinSource; 19 | public SkinPair[] skinning; 20 | public Skin customSkin; 21 | 22 | SkeletonRenderer skeletonRenderer; 23 | void Start() { 24 | skeletonRenderer = GetComponent(); 25 | Skeleton skeleton = skeletonRenderer.skeleton; 26 | 27 | customSkin = new Skin("CustomSkin"); 28 | 29 | foreach (var pair in skinning) { 30 | var attachment = SpineAttachment.GetAttachment(pair.sourceAttachment, skinSource); 31 | customSkin.AddAttachment(skeleton.FindSlotIndex(pair.targetSlot), pair.targetAttachment, attachment); 32 | } 33 | 34 | skeleton.SetSkin(customSkin); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /spine-unity/Editor/AtlasAssetInspector.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | using System; 31 | using System.Collections; 32 | using System.Collections.Generic; 33 | using System.Linq; 34 | using System.Reflection; 35 | using UnityEditor; 36 | using UnityEngine; 37 | using Spine; 38 | 39 | 40 | [CustomEditor(typeof(AtlasAsset))] 41 | public class AtlasAssetInspector : Editor { 42 | private SerializedProperty atlasFile, materials; 43 | 44 | void OnEnable () { 45 | SpineEditorUtilities.ConfirmInitialization(); 46 | atlasFile = serializedObject.FindProperty("atlasFile"); 47 | materials = serializedObject.FindProperty("materials"); 48 | } 49 | 50 | override public void OnInspectorGUI () { 51 | serializedObject.Update(); 52 | AtlasAsset asset = (AtlasAsset)target; 53 | 54 | EditorGUI.BeginChangeCheck(); 55 | EditorGUILayout.PropertyField(atlasFile); 56 | EditorGUILayout.PropertyField(materials, true); 57 | if (EditorGUI.EndChangeCheck()) 58 | serializedObject.ApplyModifiedProperties(); 59 | 60 | if (materials.arraySize == 0) { 61 | EditorGUILayout.LabelField(new GUIContent("Error: Missing materials", SpineEditorUtilities.Icons.warning)); 62 | return; 63 | } 64 | 65 | for (int i = 0; i < materials.arraySize; i++) { 66 | SerializedProperty prop = materials.GetArrayElementAtIndex(i); 67 | Material mat = (Material)prop.objectReferenceValue; 68 | if (mat == null) { 69 | EditorGUILayout.LabelField(new GUIContent("Error: Materials cannot be null", SpineEditorUtilities.Icons.warning)); 70 | return; 71 | } 72 | } 73 | 74 | 75 | 76 | if (atlasFile.objectReferenceValue != null) { 77 | Atlas atlas = asset.GetAtlas(); 78 | FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); 79 | List regions = (List)field.GetValue(atlas); 80 | EditorGUILayout.LabelField("Regions"); 81 | EditorGUI.indentLevel++; 82 | for (int i = 0; i < regions.Count; i++) { 83 | EditorGUILayout.LabelField(regions[i].name); 84 | } 85 | EditorGUI.indentLevel--; 86 | } 87 | 88 | 89 | if (serializedObject.ApplyModifiedProperties() || 90 | (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") 91 | ) { 92 | asset.Reset(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /spine-unity/Editor/BoneFollowerInspector.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | using System; 31 | using UnityEditor; 32 | using UnityEngine; 33 | 34 | [CustomEditor(typeof(BoneFollower))] 35 | public class BoneFollowerInspector : Editor { 36 | private SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation; 37 | BoneFollower component; 38 | 39 | void OnEnable () { 40 | skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); 41 | boneName = serializedObject.FindProperty("boneName"); 42 | followBoneRotation = serializedObject.FindProperty("followBoneRotation"); 43 | followZPosition = serializedObject.FindProperty("followZPosition"); 44 | component = (BoneFollower)target; 45 | ForceReload(); 46 | } 47 | 48 | void FindRenderer () { 49 | if (skeletonRenderer.objectReferenceValue == null) { 50 | SkeletonRenderer parentRenderer = SkeletonUtility.GetInParent(component.transform); 51 | 52 | if (parentRenderer != null) { 53 | skeletonRenderer.objectReferenceValue = (UnityEngine.Object)parentRenderer; 54 | } 55 | 56 | } 57 | } 58 | 59 | void ForceReload () { 60 | if (component.skeletonRenderer != null) { 61 | if (component.skeletonRenderer.valid == false) 62 | component.skeletonRenderer.Reset(); 63 | } 64 | } 65 | 66 | override public void OnInspectorGUI () { 67 | serializedObject.Update(); 68 | 69 | FindRenderer(); 70 | 71 | EditorGUILayout.PropertyField(skeletonRenderer); 72 | 73 | if (component.valid) { 74 | String[] bones = new String[1]; 75 | try { 76 | bones = new String[component.skeletonRenderer.skeleton.Data.Bones.Count + 1]; 77 | } catch { 78 | 79 | } 80 | 81 | bones[0] = ""; 82 | for (int i = 0; i < bones.Length - 1; i++) 83 | bones[i + 1] = component.skeletonRenderer.skeleton.Data.Bones[i].Name; 84 | Array.Sort(bones); 85 | int boneIndex = Math.Max(0, Array.IndexOf(bones, boneName.stringValue)); 86 | 87 | EditorGUILayout.BeginHorizontal(); 88 | EditorGUILayout.LabelField("Bone"); 89 | EditorGUIUtility.LookLikeControls(); 90 | boneIndex = EditorGUILayout.Popup(boneIndex, bones); 91 | EditorGUILayout.EndHorizontal(); 92 | 93 | boneName.stringValue = boneIndex == 0 ? null : bones[boneIndex]; 94 | EditorGUILayout.PropertyField(followBoneRotation); 95 | EditorGUILayout.PropertyField(followZPosition); 96 | } else { 97 | GUILayout.Label("INVALID"); 98 | } 99 | 100 | if (serializedObject.ApplyModifiedProperties() || 101 | (Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed") 102 | ) { 103 | component.Reset(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-animation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-animation.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-animationRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-animationRoot.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-bone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-bone.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-boneNib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-boneNib.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-boundingBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-boundingBox.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-constraintNib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-constraintNib.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-event.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-hingeChain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-hingeChain.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-image.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-mesh.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-null.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-poseBones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-poseBones.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-skeleton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-skeleton.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-skeletonUtility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-skeletonUtility.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-skin.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-skinPlaceholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-skinPlaceholder.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-skinsRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-skinsRoot.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-slot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-slot.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-slotRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-slotRoot.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-spine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-spine.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-subMeshRenderer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-subMeshRenderer.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-warning.png -------------------------------------------------------------------------------- /spine-unity/Editor/GUI/icon-weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506638093/spine-optimize/108ef88947039b943a4886215750672fe9e45ff7/spine-unity/Editor/GUI/icon-weights.png -------------------------------------------------------------------------------- /spine-unity/Editor/Menus.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | using System; 31 | using System.IO; 32 | using UnityEditor; 33 | using UnityEngine; 34 | using Spine; 35 | 36 | public class Menus { 37 | [MenuItem("Assets/Create/Spine Atlas")] 38 | static public void CreateAtlas () { 39 | CreateAsset("New Atlas"); 40 | } 41 | 42 | [MenuItem("Assets/Create/Spine SkeletonData")] 43 | static public void CreateSkeletonData () { 44 | CreateAsset("New SkeletonData"); 45 | } 46 | 47 | static private void CreateAsset (String name) where T : ScriptableObject { 48 | var dir = "Assets/"; 49 | var selected = Selection.activeObject; 50 | if (selected != null) { 51 | var assetDir = AssetDatabase.GetAssetPath(selected.GetInstanceID()); 52 | if (assetDir.Length > 0 && Directory.Exists(assetDir)) 53 | dir = assetDir + "/"; 54 | } 55 | ScriptableObject asset = ScriptableObject.CreateInstance(); 56 | AssetDatabase.CreateAsset(asset, dir + name + ".asset"); 57 | AssetDatabase.SaveAssets(); 58 | EditorUtility.FocusProjectWindow(); 59 | Selection.activeObject = asset; 60 | } 61 | 62 | [MenuItem("GameObject/Create Other/Spine SkeletonRenderer")] 63 | static public void CreateSkeletonRendererGameObject () { 64 | GameObject gameObject = new GameObject("New SkeletonRenderer", typeof(SkeletonRenderer)); 65 | EditorUtility.FocusProjectWindow(); 66 | Selection.activeObject = gameObject; 67 | } 68 | 69 | [MenuItem("GameObject/Create Other/Spine SkeletonAnimation")] 70 | static public void CreateSkeletonAnimationGameObject () { 71 | GameObject gameObject = new GameObject("New SkeletonAnimation", typeof(SkeletonAnimation)); 72 | EditorUtility.FocusProjectWindow(); 73 | Selection.activeObject = gameObject; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /spine-unity/Editor/SkeletonAnimationInspector.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | using System; 31 | using UnityEditor; 32 | using UnityEngine; 33 | using Spine; 34 | 35 | [CustomEditor(typeof(SkeletonAnimation))] 36 | public class SkeletonAnimationInspector : SkeletonRendererInspector { 37 | protected SerializedProperty animationName, loop, timeScale; 38 | protected bool isPrefab; 39 | 40 | protected override void OnEnable () { 41 | base.OnEnable(); 42 | animationName = serializedObject.FindProperty("_animationName"); 43 | loop = serializedObject.FindProperty("loop"); 44 | timeScale = serializedObject.FindProperty("timeScale"); 45 | 46 | if (PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab) 47 | isPrefab = true; 48 | 49 | 50 | } 51 | 52 | protected override void gui () { 53 | base.gui(); 54 | 55 | SkeletonAnimation component = (SkeletonAnimation)target; 56 | if (!component.valid) 57 | return; 58 | 59 | //catch case where SetAnimation was used to set track 0 without using AnimationName 60 | if (Application.isPlaying) { 61 | TrackEntry currentState = component.state.GetCurrent(0); 62 | if (currentState != null) { 63 | if (component.AnimationName != animationName.stringValue) { 64 | animationName.stringValue = currentState.Animation.Name; 65 | } 66 | } 67 | } 68 | 69 | EditorGUILayout.Space(); 70 | 71 | //TODO: Refactor this to use GenericMenu and callbacks to avoid interfering with control by other behaviours. 72 | // Animation name. 73 | { 74 | String[] animations = new String[component.skeleton.Data.Animations.Count + 1]; 75 | animations[0] = ""; 76 | int animationIndex = 0; 77 | for (int i = 0; i < animations.Length - 1; i++) { 78 | String name = component.skeleton.Data.Animations[i].Name; 79 | animations[i + 1] = name; 80 | if (name == animationName.stringValue) 81 | animationIndex = i + 1; 82 | } 83 | 84 | animationIndex = EditorGUILayout.Popup("Animation", animationIndex, animations); 85 | String selectedAnimationName = animationIndex == 0 ? null : animations[animationIndex]; 86 | if (component.AnimationName != selectedAnimationName) { 87 | component.AnimationName = selectedAnimationName; 88 | animationName.stringValue = selectedAnimationName; 89 | } 90 | 91 | } 92 | 93 | EditorGUILayout.PropertyField(loop); 94 | EditorGUILayout.PropertyField(timeScale); 95 | component.timeScale = Math.Max(component.timeScale, 0); 96 | 97 | EditorGUILayout.Space(); 98 | 99 | if (!isPrefab) { 100 | if (component.GetComponent() == null) { 101 | if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))) { 102 | component.gameObject.AddComponent(); 103 | } 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /spine-unity/Editor/SkeletonAnimatorInspector.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | /***************************************************************************** 32 | * SkeletonAnimatorInspector created by Mitch Thompson 33 | * Full irrevocable rights and permissions granted to Esoteric Software 34 | *****************************************************************************/ 35 | using System; 36 | using UnityEditor; 37 | using UnityEngine; 38 | using Spine; 39 | 40 | [CustomEditor(typeof(SkeletonAnimator))] 41 | public class SkeletonAnimatorInspector : SkeletonRendererInspector { 42 | protected SerializedProperty layerMixModes; 43 | protected bool isPrefab; 44 | protected override void OnEnable () { 45 | base.OnEnable(); 46 | layerMixModes = serializedObject.FindProperty("layerMixModes"); 47 | 48 | if (PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab) 49 | isPrefab = true; 50 | } 51 | 52 | protected override void gui () { 53 | base.gui(); 54 | 55 | EditorGUILayout.PropertyField(layerMixModes, true); 56 | 57 | SkeletonAnimator component = (SkeletonAnimator)target; 58 | if (!component.valid) 59 | return; 60 | 61 | EditorGUILayout.Space(); 62 | 63 | if (!isPrefab) { 64 | if (component.GetComponent() == null) { 65 | if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))) { 66 | component.gameObject.AddComponent(); 67 | } 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /spine-unity/Editor/SkeletonRendererInspector.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | using System; 31 | using System.Reflection; 32 | using UnityEditor; 33 | using UnityEngine; 34 | 35 | [CustomEditor(typeof(SkeletonRenderer))] 36 | public class SkeletonRendererInspector : Editor { 37 | protected static bool advancedFoldout; 38 | 39 | protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, submeshSeparators, front; 40 | 41 | private static MethodInfo EditorGUILayoutSortingLayerField; 42 | protected SerializedObject rendererSerializedObject; 43 | protected SerializedProperty sortingLayerIDProperty; 44 | 45 | protected virtual void OnEnable () { 46 | SpineEditorUtilities.ConfirmInitialization(); 47 | skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset"); 48 | initialSkinName = serializedObject.FindProperty("initialSkinName"); 49 | normals = serializedObject.FindProperty("calculateNormals"); 50 | tangents = serializedObject.FindProperty("calculateTangents"); 51 | meshes = serializedObject.FindProperty("renderMeshes"); 52 | immutableTriangles = serializedObject.FindProperty("immutableTriangles"); 53 | submeshSeparators = serializedObject.FindProperty("submeshSeparators"); 54 | front = serializedObject.FindProperty("frontFacing"); 55 | 56 | if(EditorGUILayoutSortingLayerField == null) 57 | EditorGUILayoutSortingLayerField = typeof(EditorGUILayout).GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle) }, null); 58 | 59 | rendererSerializedObject = new SerializedObject(((SkeletonRenderer)target).GetComponent()); 60 | sortingLayerIDProperty = rendererSerializedObject.FindProperty("m_SortingLayerID"); 61 | } 62 | 63 | protected virtual void gui () { 64 | SkeletonRenderer component = (SkeletonRenderer)target; 65 | EditorGUILayout.BeginHorizontal(); 66 | EditorGUILayout.PropertyField(skeletonDataAsset); 67 | float reloadWidth = GUI.skin.label.CalcSize(new GUIContent("Reload")).x + 20; 68 | if (GUILayout.Button("Reload", GUILayout.Width(reloadWidth))) { 69 | if (component.skeletonDataAsset != null) { 70 | foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { 71 | if (aa != null) 72 | aa.Reset(); 73 | } 74 | 75 | component.skeletonDataAsset.Reset(); 76 | } 77 | component.Reset(); 78 | } 79 | EditorGUILayout.EndHorizontal(); 80 | 81 | if (!component.valid) { 82 | component.Reset(); 83 | component.LateUpdate(); 84 | if (!component.valid) 85 | return; 86 | } 87 | 88 | // Initial skin name. 89 | { 90 | String[] skins = new String[component.skeleton.Data.Skins.Count]; 91 | int skinIndex = 0; 92 | for (int i = 0; i < skins.Length; i++) { 93 | String name = component.skeleton.Data.Skins[i].Name; 94 | skins[i] = name; 95 | if (name == initialSkinName.stringValue) 96 | skinIndex = i; 97 | } 98 | 99 | skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins); 100 | initialSkinName.stringValue = skins[skinIndex]; 101 | } 102 | 103 | EditorGUILayout.Space(); 104 | 105 | // Sorting Layers 106 | { 107 | var renderer = component.GetComponent(); 108 | if(renderer != null) { 109 | EditorGUI.BeginChangeCheck(); 110 | 111 | if(EditorGUILayoutSortingLayerField != null && sortingLayerIDProperty != null) { 112 | EditorGUILayoutSortingLayerField.Invoke(null, new object[] { new GUIContent("Sorting Layer"), sortingLayerIDProperty, EditorStyles.popup } ); 113 | } else { 114 | renderer.sortingLayerID = EditorGUILayout.IntField("Sorting Layer ID", renderer.sortingLayerID); 115 | } 116 | 117 | renderer.sortingOrder = EditorGUILayout.IntField("Order in Layer", renderer.sortingOrder); 118 | 119 | if(EditorGUI.EndChangeCheck()) { 120 | rendererSerializedObject.ApplyModifiedProperties(); 121 | EditorUtility.SetDirty(renderer); 122 | } 123 | } 124 | } 125 | 126 | // More Render Options... 127 | { 128 | advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced"); 129 | if(advancedFoldout) { 130 | EditorGUI.indentLevel++; 131 | EditorGUILayout.PropertyField(meshes, 132 | new GUIContent("Render Meshes", "Disable to optimize rendering for skeletons that don't use meshes")); 133 | EditorGUILayout.PropertyField(immutableTriangles, 134 | new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility")); 135 | EditorGUILayout.PropertyField(normals); 136 | EditorGUILayout.PropertyField(tangents); 137 | EditorGUILayout.PropertyField(front); 138 | EditorGUILayout.PropertyField(submeshSeparators, true); 139 | EditorGUI.indentLevel--; 140 | } 141 | } 142 | } 143 | 144 | override public void OnInspectorGUI () { 145 | serializedObject.Update(); 146 | gui(); 147 | if (serializedObject.ApplyModifiedProperties() || 148 | (Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed") 149 | ) { 150 | if (!Application.isPlaying) 151 | ((SkeletonRenderer)target).Reset(); 152 | } 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /spine-unity/Shaders/Bones.shader: -------------------------------------------------------------------------------- 1 | // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' 2 | 3 | Shader "Spine/Bones" { 4 | Properties { 5 | _Color ("Color", Color) = (0.5,0.5,0.5,0.5) 6 | _MainTex ("Particle Texture", 2D) = "white" {} 7 | } 8 | 9 | Category { 10 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } 11 | Blend SrcAlpha OneMinusSrcAlpha 12 | AlphaTest Greater .01 13 | ColorMask RGB 14 | 15 | Lighting Off Cull Off ZTest Always ZWrite Off Fog { Mode Off } 16 | 17 | SubShader { 18 | Pass { 19 | 20 | CGPROGRAM 21 | #pragma vertex vert 22 | #pragma fragment frag 23 | #pragma multi_compile_particles 24 | 25 | #include "UnityCG.cginc" 26 | 27 | sampler2D _MainTex; 28 | fixed4 _Color; 29 | 30 | struct appdata_t { 31 | float4 vertex : POSITION; 32 | fixed4 color : COLOR; 33 | float2 texcoord : TEXCOORD0; 34 | }; 35 | 36 | struct v2f { 37 | float4 vertex : SV_POSITION; 38 | fixed4 color : COLOR; 39 | float2 texcoord : TEXCOORD0; 40 | #ifdef SOFTPARTICLES_ON 41 | float4 projPos : TEXCOORD1; 42 | #endif 43 | }; 44 | 45 | float4 _MainTex_ST; 46 | 47 | v2f vert (appdata_t v) 48 | { 49 | v2f o; 50 | o.vertex = UnityObjectToClipPos(v.vertex); 51 | #ifdef SOFTPARTICLES_ON 52 | o.projPos = ComputeScreenPos (o.vertex); 53 | COMPUTE_EYEDEPTH(o.projPos.z); 54 | #endif 55 | o.color = v.color; 56 | o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); 57 | return o; 58 | } 59 | 60 | sampler2D_float _CameraDepthTexture; 61 | 62 | 63 | fixed4 frag (v2f i) : SV_Target 64 | { 65 | return 2.0f * i.color * _Color * tex2D(_MainTex, i.texcoord); 66 | } 67 | ENDCG 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /spine-unity/Shaders/HiddenPass.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: HiddenPass 11 | m_Shader: {fileID: 4800000, guid: 913475501bf19374c84390868a9d6d3d, type: 3} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _MainTex: 23 | m_Texture: {fileID: 0} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | m_Floats: 27 | - _Cutoff: 0.1 28 | - _InvFade: 1 29 | m_Colors: 30 | - _Color: {r: 1, g: 1, b: 1, a: 1} 31 | - _TintColor: {r: 0.5, g: 0.5, b: 0.5, a: 0} 32 | -------------------------------------------------------------------------------- /spine-unity/Shaders/HiddenPass.shader: -------------------------------------------------------------------------------- 1 | Shader "Spine/HiddenPass" { 2 | SubShader 3 | 4 | { 5 | 6 | Tags {"Queue" = "Geometry-1" } 7 | 8 | Lighting Off 9 | 10 | Pass 11 | 12 | { 13 | 14 | ZWrite Off 15 | 16 | ColorMask 0 17 | 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spine-unity/Shaders/SkeletonLit.shader: -------------------------------------------------------------------------------- 1 | Shader "Spine/Skeleton Lit" { 2 | Properties { 3 | _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 4 | _MainTex ("Texture to blend", 2D) = "black" {} 5 | } 6 | // 2 texture stage GPUs 7 | SubShader { 8 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } 9 | LOD 100 10 | 11 | Cull Off 12 | ZWrite Off 13 | Blend One OneMinusSrcAlpha 14 | 15 | Pass { 16 | Tags { "LightMode"="Vertex" } 17 | ColorMaterial AmbientAndDiffuse 18 | Lighting On 19 | SetTexture [_MainTex] { 20 | Combine texture * primary DOUBLE, texture * primary 21 | } 22 | } 23 | 24 | Pass { 25 | Name "Caster" 26 | Tags { "LightMode"="ShadowCaster" } 27 | Offset 1, 1 28 | 29 | Fog { Mode Off } 30 | ZWrite On 31 | ZTest LEqual 32 | Cull Off 33 | Lighting Off 34 | 35 | CGPROGRAM 36 | #pragma vertex vert 37 | #pragma fragment frag 38 | #pragma multi_compile_shadowcaster 39 | #pragma fragmentoption ARB_precision_hint_fastest 40 | #include "UnityCG.cginc" 41 | struct v2f { 42 | V2F_SHADOW_CASTER; 43 | float2 uv : TEXCOORD1; 44 | }; 45 | 46 | uniform float4 _MainTex_ST; 47 | 48 | v2f vert (appdata_base v) { 49 | v2f o; 50 | TRANSFER_SHADOW_CASTER(o) 51 | o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); 52 | return o; 53 | } 54 | 55 | uniform sampler2D _MainTex; 56 | uniform fixed _Cutoff; 57 | 58 | float4 frag (v2f i) : COLOR { 59 | fixed4 texcol = tex2D(_MainTex, i.uv); 60 | clip(texcol.a - _Cutoff); 61 | SHADOW_CASTER_FRAGMENT(i) 62 | } 63 | ENDCG 64 | } 65 | } 66 | // 1 texture stage GPUs 67 | SubShader { 68 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } 69 | LOD 100 70 | 71 | Cull Off 72 | ZWrite Off 73 | Blend One OneMinusSrcAlpha 74 | 75 | Pass { 76 | Tags { "LightMode"="Vertex" } 77 | ColorMaterial AmbientAndDiffuse 78 | Lighting On 79 | SetTexture [_MainTex] { 80 | Combine texture * primary DOUBLE, texture * primary 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /spine-unity/Shaders/Spine-Skeleton-BlendMode.shader: -------------------------------------------------------------------------------- 1 | Shader "Spine/Skeleton-BlendMode" { 2 | Properties { 3 | _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 4 | [HDR]_Color("Color", Color) = (1,1,1,1) 5 | [Enum(UnityEngine.Rendering.BlendOp)] _BlendOp("Blend Op", Float) = 0.0 6 | [Enum(UnityEngine.Rendering.BlendMode)]_SrcBlend("Src Blend Mode", Int) = 0 7 | [Enum(UnityEngine.Rendering.BlendMode)]_DstBlend("Dst Blend Mode", Int) = 0 8 | [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} 9 | [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 1 10 | [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 11 | [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default 12 | 13 | // Outline properties are drawn via custom editor. 14 | [HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0 15 | [HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1) 16 | [HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024 17 | [HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25 18 | [HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0 19 | [HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1 20 | [HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0 21 | 22 | [HideInInspector] _OpenMask("openMask",Int) = 0 23 | [HideInInspector] _Area("Area",Vector) = (0,0,1,1) 24 | } 25 | 26 | SubShader { 27 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } 28 | 29 | Fog { Mode Off } 30 | BlendOp[_BlendOp] 31 | Blend[_SrcBlend][_DstBlend] 32 | Cull Off 33 | ZWrite Off 34 | Lighting Off 35 | 36 | Stencil { 37 | Ref[_StencilRef] 38 | Comp[_StencilComp] 39 | Pass Keep 40 | } 41 | 42 | CGINCLUDE 43 | 44 | #include "UnityCG.cginc" 45 | 46 | float4 _Color; 47 | sampler2D _MainTex; 48 | 49 | struct VertexInput { 50 | float4 vertex : POSITION; 51 | float2 uv : TEXCOORD0; 52 | float4 vertexColor : COLOR; 53 | }; 54 | 55 | struct DistortionOutput { 56 | float4 pos : SV_POSITION; 57 | float2 uv : TEXCOORD0; 58 | float4 vertexColor : COLOR; 59 | }; 60 | 61 | DistortionOutput vertDistortion(VertexInput v) { 62 | DistortionOutput o; 63 | o.pos = UnityObjectToClipPos(v.vertex); 64 | o.uv = v.uv; 65 | o.vertexColor = v.vertexColor; 66 | return o; 67 | } 68 | 69 | ENDCG 70 | 71 | // Normal 72 | Pass { 73 | Name "Normal" 74 | 75 | CGPROGRAM 76 | #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT 77 | #pragma vertex vert 78 | #pragma fragment frag 79 | 80 | float4 _Area; 81 | int _OpenMask; 82 | 83 | struct VertexOutput { 84 | float4 pos : SV_POSITION; 85 | float2 uv : TEXCOORD0; 86 | float4 vertexColor : COLOR; 87 | float2 worldPos:TEXCOORD1; 88 | }; 89 | 90 | VertexOutput vert (VertexInput v) { 91 | VertexOutput o; 92 | o.pos = UnityObjectToClipPos(v.vertex); 93 | o.uv = v.uv; 94 | o.vertexColor = v.vertexColor; 95 | o.worldPos = mul(unity_ObjectToWorld,v.vertex).xy; 96 | return o; 97 | } 98 | 99 | sampler2D _CameraDepthTexture; 100 | float _InvFade; 101 | 102 | float4 frag (VertexOutput i) : SV_Target { 103 | float4 texColor = tex2D(_MainTex, i.uv) * _Color; 104 | 105 | #if defined(_STRAIGHT_ALPHA_INPUT) 106 | texColor.rgb *= texColor.a; 107 | #endif 108 | 109 | bool inArea = true; 110 | if ( _OpenMask == 1) 111 | inArea = i.worldPos.x >= _Area.x && i.worldPos.x <= _Area.z && i.worldPos.y >= _Area.y && i.worldPos.y <= _Area.w; 112 | 113 | return inArea? (texColor * i.vertexColor):fixed4(0,0,0,0); 114 | } 115 | ENDCG 116 | } 117 | 118 | // SkillDistortion 119 | Pass { 120 | Name "SkillDistortionObject" 121 | 122 | Tags {"LightMode"="SkillDistortionObject"} 123 | 124 | CGPROGRAM 125 | #pragma vertex vertDistortion 126 | #pragma fragment frag 127 | 128 | float4 frag(DistortionOutput i) : SV_Target { 129 | float4 texColor = tex2D(_MainTex, i.uv) * i.vertexColor; 130 | return texColor.aaaa; 131 | } 132 | ENDCG 133 | } 134 | 135 | Pass { 136 | Name "Caster" 137 | Tags { "LightMode"="ShadowCaster" } 138 | Offset 1, 1 139 | ZWrite On 140 | ZTest LEqual 141 | 142 | Fog { Mode Off } 143 | Cull Off 144 | Lighting Off 145 | 146 | CGPROGRAM 147 | #pragma vertex vert 148 | #pragma fragment frag 149 | #pragma multi_compile_shadowcaster 150 | #pragma fragmentoption ARB_precision_hint_fastest 151 | fixed _Cutoff; 152 | 153 | struct VertexOutput { 154 | V2F_SHADOW_CASTER; 155 | float4 uvAndAlpha : TEXCOORD1; 156 | }; 157 | 158 | VertexOutput vert (appdata_base v, float4 vertexColor : COLOR) { 159 | VertexOutput o; 160 | o.uvAndAlpha = v.texcoord; 161 | o.uvAndAlpha.a = vertexColor.a; 162 | TRANSFER_SHADOW_CASTER(o) 163 | return o; 164 | } 165 | 166 | float4 frag (VertexOutput i) : SV_Target { 167 | fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy); 168 | clip(texcol.a * i.uvAndAlpha.a - _Cutoff); 169 | SHADOW_CASTER_FRAGMENT(i) 170 | } 171 | ENDCG 172 | } 173 | } 174 | CustomEditor "SpineShaderWithOutlineGUI" 175 | } 176 | -------------------------------------------------------------------------------- /spine-unity/Shaders/Spine-Skeleton-HDR.shader: -------------------------------------------------------------------------------- 1 | Shader "Spine/SkeletonHDR" { 2 | Properties { 3 | [HDR] _HDRColor("HDR Color", Color) = (1,1,1,1) 4 | _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 5 | [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} 6 | [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 1 7 | [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 8 | [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default 9 | 10 | // Outline properties are drawn via custom editor. 11 | [HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0 12 | [HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1) 13 | [HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024 14 | [HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25 15 | [HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0 16 | [HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1 17 | [HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0 18 | 19 | [HideInInspector] _OpenMask("openMask",Int) = 0 20 | [HideInInspector] _Area("Area",Vector) = (0,0,1,1) 21 | } 22 | 23 | SubShader { 24 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } 25 | 26 | Pass //2d shadow 27 | { 28 | Stencil 29 | { 30 | Ref 0 31 | Comp equal 32 | Pass incrWrap 33 | Fail keep 34 | ZFail keep 35 | } 36 | 37 | Tags { "LightMode" = "ForwardBase" } 38 | Blend SrcAlpha OneMinusSrcAlpha 39 | 40 | Cull Off 41 | ZWrite Off 42 | 43 | Name "2d shadow" 44 | CGPROGRAM 45 | #pragma vertex vert 46 | #pragma fragment frag 47 | #pragma target 2.0 48 | 49 | #include "UnityCG.cginc" 50 | 51 | struct VertexInput { 52 | float4 vertex : POSITION; 53 | float4 color : COLOR; 54 | float2 texcoord : TEXCOORD0; 55 | UNITY_VERTEX_INPUT_INSTANCE_ID 56 | }; 57 | 58 | struct VertexOutput { 59 | float4 vertex : SV_POSITION; 60 | fixed4 color : COLOR; 61 | half2 texcoord : TEXCOORD0; 62 | float4 worldPosition : TEXCOORD1; 63 | UNITY_VERTEX_OUTPUT_STEREO 64 | }; 65 | 66 | float _DirectionalLightStrength; 67 | float4x4 _DirectionalLightMatrix; 68 | half4 _DirectionalLightShadowColor; 69 | 70 | VertexOutput vert(VertexInput IN) { 71 | VertexOutput OUT; 72 | 73 | UNITY_SETUP_INSTANCE_ID(IN); 74 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 75 | 76 | float3 WorldPos = mul(_DirectionalLightMatrix, IN.vertex).xyz; 77 | OUT.vertex = mul(UNITY_MATRIX_VP, float4(WorldPos, 1)); 78 | 79 | OUT.texcoord = IN.texcoord; 80 | 81 | OUT.color = _DirectionalLightShadowColor.rgba * 0.2; 82 | OUT.color.a = IN.color.a * _DirectionalLightStrength; 83 | 84 | return OUT; 85 | } 86 | 87 | sampler2D _MainTex; 88 | 89 | fixed4 frag(VertexOutput IN) : SV_Target 90 | { 91 | fixed4 color = IN.color; 92 | half alpha = tex2D(_MainTex, IN.texcoord).a * color.a; 93 | clip(alpha - 0.001); 94 | 95 | return color; 96 | } 97 | ENDCG 98 | } 99 | 100 | Pass 101 | { 102 | 103 | Stencil 104 | { 105 | Ref [_StencilRef] 106 | Comp [_StencilComp] 107 | Pass Keep 108 | } 109 | 110 | Name "Normal" 111 | 112 | Fog { Mode Off } 113 | Cull Off 114 | ZWrite Off 115 | Blend One OneMinusSrcAlpha 116 | Lighting Off 117 | 118 | CGPROGRAM 119 | #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT 120 | #pragma vertex vert 121 | #pragma fragment frag 122 | #include "UnityCG.cginc" 123 | sampler2D _MainTex; 124 | 125 | float4 _Area; 126 | int _OpenMask; 127 | float4 _HDRColor; 128 | 129 | struct VertexInput { 130 | float4 vertex : POSITION; 131 | float2 uv : TEXCOORD0; 132 | float4 vertexColor : COLOR; 133 | }; 134 | 135 | struct VertexOutput { 136 | float4 pos : SV_POSITION; 137 | float2 uv : TEXCOORD0; 138 | float4 vertexColor : COLOR; 139 | float2 worldPos:TEXCOORD1; 140 | }; 141 | 142 | VertexOutput vert (VertexInput v) { 143 | VertexOutput o; 144 | o.pos = UnityObjectToClipPos(v.vertex); 145 | o.uv = v.uv; 146 | o.vertexColor = v.vertexColor; 147 | o.worldPos = mul(unity_ObjectToWorld,v.vertex).xy; 148 | return o; 149 | } 150 | 151 | sampler2D _CameraDepthTexture; 152 | float _InvFade; 153 | 154 | float4 frag (VertexOutput i) : SV_Target { 155 | float4 texColor = tex2D(_MainTex, i.uv) * _HDRColor; 156 | 157 | #if defined(_STRAIGHT_ALPHA_INPUT) 158 | texColor.rgb *= texColor.a; 159 | #endif 160 | 161 | bool inArea = true; 162 | if ( _OpenMask == 1) 163 | inArea = i.worldPos.x >= _Area.x && i.worldPos.x <= _Area.z && i.worldPos.y >= _Area.y && i.worldPos.y <= _Area.w; 164 | 165 | return inArea? (texColor * i.vertexColor):fixed4(0,0,0,0); 166 | } 167 | ENDCG 168 | } 169 | 170 | Pass 171 | { 172 | Name "Caster" 173 | Tags { "LightMode"="ShadowCaster" } 174 | Offset 1, 1 175 | ZWrite On 176 | ZTest LEqual 177 | 178 | Fog { Mode Off } 179 | Cull Off 180 | Lighting Off 181 | Blend One OneMinusSrcAlpha 182 | 183 | CGPROGRAM 184 | #pragma vertex vert 185 | #pragma fragment frag 186 | #pragma multi_compile_shadowcaster 187 | #pragma fragmentoption ARB_precision_hint_fastest 188 | #include "UnityCG.cginc" 189 | sampler2D _MainTex; 190 | fixed _Cutoff; 191 | 192 | struct VertexOutput { 193 | V2F_SHADOW_CASTER; 194 | float4 uvAndAlpha : TEXCOORD1; 195 | }; 196 | 197 | VertexOutput vert (appdata_base v, float4 vertexColor : COLOR) { 198 | VertexOutput o; 199 | o.uvAndAlpha = v.texcoord; 200 | o.uvAndAlpha.a = vertexColor.a; 201 | TRANSFER_SHADOW_CASTER(o) 202 | return o; 203 | } 204 | 205 | float4 frag (VertexOutput i) : SV_Target { 206 | fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy); 207 | clip(texcol.a * i.uvAndAlpha.a - _Cutoff); 208 | SHADOW_CASTER_FRAGMENT(i) 209 | } 210 | ENDCG 211 | } 212 | } 213 | CustomEditor "SpineShaderWithOutlineGUI" 214 | } 215 | -------------------------------------------------------------------------------- /spine-unity/Shaders/Spine-Skeleton.shader: -------------------------------------------------------------------------------- 1 | Shader "Spine/Skeleton" { 2 | Properties { 3 | _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 4 | [NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {} 5 | [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 1 6 | [HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0 7 | [HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default 8 | 9 | // Outline properties are drawn via custom editor. 10 | [HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0 11 | [HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1) 12 | [HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024 13 | [HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25 14 | [HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0 15 | [HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1 16 | [HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0 17 | 18 | [HideInInspector] _OpenMask("openMask",Int) = 0 19 | [HideInInspector] _Area("Area",Vector) = (0,0,1,1) 20 | } 21 | 22 | SubShader { 23 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } 24 | 25 | Fog { Mode Off } 26 | Cull Off 27 | ZWrite Off 28 | Blend One OneMinusSrcAlpha 29 | Lighting Off 30 | 31 | Stencil { 32 | Ref[_StencilRef] 33 | Comp[_StencilComp] 34 | Pass Keep 35 | } 36 | 37 | CGINCLUDE 38 | 39 | #include "UnityCG.cginc" 40 | 41 | sampler2D _MainTex; 42 | 43 | struct VertexInput { 44 | float4 vertex : POSITION; 45 | float2 uv : TEXCOORD0; 46 | float4 vertexColor : COLOR; 47 | }; 48 | 49 | struct DistortionOutput { 50 | float4 pos : SV_POSITION; 51 | float2 uv : TEXCOORD0; 52 | float4 vertexColor : COLOR; 53 | }; 54 | 55 | DistortionOutput vertDistortion(VertexInput v) { 56 | DistortionOutput o; 57 | o.pos = UnityObjectToClipPos(v.vertex); 58 | o.uv = v.uv; 59 | o.vertexColor = v.vertexColor; 60 | return o; 61 | } 62 | 63 | ENDCG 64 | 65 | // Normal 66 | Pass { 67 | Name "Normal" 68 | 69 | CGPROGRAM 70 | #pragma shader_feature _ _STRAIGHT_ALPHA_INPUT 71 | #pragma vertex vert 72 | #pragma fragment frag 73 | 74 | float4 _Area; 75 | int _OpenMask; 76 | 77 | struct VertexOutput { 78 | float4 pos : SV_POSITION; 79 | float2 uv : TEXCOORD0; 80 | float4 vertexColor : COLOR; 81 | float2 worldPos:TEXCOORD1; 82 | }; 83 | 84 | VertexOutput vert (VertexInput v) { 85 | VertexOutput o; 86 | o.pos = UnityObjectToClipPos(v.vertex); 87 | o.uv = v.uv; 88 | o.vertexColor = v.vertexColor; 89 | o.worldPos = mul(unity_ObjectToWorld,v.vertex).xy; 90 | return o; 91 | } 92 | 93 | sampler2D _CameraDepthTexture; 94 | float _InvFade; 95 | 96 | float4 frag (VertexOutput i) : SV_Target { 97 | float4 texColor = tex2D(_MainTex, i.uv); 98 | 99 | #if defined(_STRAIGHT_ALPHA_INPUT) 100 | texColor.rgb *= texColor.a; 101 | #endif 102 | 103 | bool inArea = true; 104 | if ( _OpenMask == 1) 105 | inArea = i.worldPos.x >= _Area.x && i.worldPos.x <= _Area.z && i.worldPos.y >= _Area.y && i.worldPos.y <= _Area.w; 106 | 107 | return inArea? (texColor * i.vertexColor):fixed4(0,0,0,0); 108 | } 109 | ENDCG 110 | } 111 | 112 | // SkillDistortion 113 | Pass { 114 | Name "SkillDistortionObject" 115 | 116 | Tags {"LightMode"="SkillDistortionObject"} 117 | 118 | CGPROGRAM 119 | #pragma vertex vertDistortion 120 | #pragma fragment frag 121 | 122 | float4 frag(DistortionOutput i) : SV_Target { 123 | float4 texColor = tex2D(_MainTex, i.uv) * i.vertexColor; 124 | return texColor.aaaa; 125 | } 126 | ENDCG 127 | } 128 | 129 | Pass { 130 | Name "Caster" 131 | Tags { "LightMode"="ShadowCaster" } 132 | Offset 1, 1 133 | ZWrite On 134 | ZTest LEqual 135 | 136 | Fog { Mode Off } 137 | Cull Off 138 | Lighting Off 139 | 140 | CGPROGRAM 141 | #pragma vertex vert 142 | #pragma fragment frag 143 | #pragma multi_compile_shadowcaster 144 | #pragma fragmentoption ARB_precision_hint_fastest 145 | fixed _Cutoff; 146 | 147 | struct VertexOutput { 148 | V2F_SHADOW_CASTER; 149 | float4 uvAndAlpha : TEXCOORD1; 150 | }; 151 | 152 | VertexOutput vert (appdata_base v, float4 vertexColor : COLOR) { 153 | VertexOutput o; 154 | o.uvAndAlpha = v.texcoord; 155 | o.uvAndAlpha.a = vertexColor.a; 156 | TRANSFER_SHADOW_CASTER(o) 157 | return o; 158 | } 159 | 160 | float4 frag (VertexOutput i) : SV_Target { 161 | fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy); 162 | clip(texcol.a * i.uvAndAlpha.a - _Cutoff); 163 | SHADOW_CASTER_FRAGMENT(i) 164 | } 165 | ENDCG 166 | } 167 | } 168 | CustomEditor "SpineShaderWithOutlineGUI" 169 | } 170 | -------------------------------------------------------------------------------- /spine-unity/SkeletonAnimationInterface.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public delegate void UpdateBonesDelegate (SkeletonRenderer skeletonRenderer); 5 | public interface ISkeletonAnimation { 6 | event UpdateBonesDelegate UpdateLocal; 7 | event UpdateBonesDelegate UpdateWorld; 8 | event UpdateBonesDelegate UpdateComplete; 9 | 10 | void LateUpdate (); 11 | } -------------------------------------------------------------------------------- /spine-unity/SkeletonAnimator.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | /***************************************************************************** 32 | * SkeletonAnimator created by Mitch Thompson 33 | * Full irrevocable rights and permissions granted to Esoteric Software 34 | *****************************************************************************/ 35 | using UnityEngine; 36 | using System.Collections; 37 | using System.Collections.Generic; 38 | using Spine; 39 | 40 | [RequireComponent(typeof(Animator))] 41 | public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation { 42 | 43 | public enum MixMode { AlwaysMix, MixNext, SpineStyle } 44 | public MixMode[] layerMixModes = new MixMode[0]; 45 | 46 | public event UpdateBonesDelegate UpdateLocal { 47 | add { _UpdateLocal += value; } 48 | remove { _UpdateLocal -= value; } 49 | } 50 | 51 | public event UpdateBonesDelegate UpdateWorld { 52 | add { _UpdateWorld += value; } 53 | remove { _UpdateWorld -= value; } 54 | } 55 | 56 | public event UpdateBonesDelegate UpdateComplete { 57 | add { _UpdateComplete += value; } 58 | remove { _UpdateComplete -= value; } 59 | } 60 | 61 | protected event UpdateBonesDelegate _UpdateLocal; 62 | protected event UpdateBonesDelegate _UpdateWorld; 63 | protected event UpdateBonesDelegate _UpdateComplete; 64 | 65 | Dictionary animationTable = new Dictionary(); 66 | Animator animator; 67 | 68 | public override void Reset () { 69 | base.Reset(); 70 | if (!valid) 71 | return; 72 | 73 | animationTable.Clear(); 74 | 75 | var data = skeletonDataAsset.GetSkeletonData(true); 76 | 77 | foreach (var a in data.Animations) { 78 | animationTable.Add(a.Name, a); 79 | } 80 | 81 | animator = GetComponent(); 82 | 83 | 84 | } 85 | 86 | void Update () { 87 | if (!valid) 88 | return; 89 | 90 | if (layerMixModes.Length != animator.layerCount) { 91 | System.Array.Resize(ref layerMixModes, animator.layerCount); 92 | } 93 | 94 | skeleton.Update(Time.deltaTime); 95 | 96 | //apply 97 | int layerCount = animator.layerCount; 98 | float deltaTime = Time.deltaTime; 99 | for (int i = 0; i < layerCount; i++) { 100 | 101 | float layerWeight = animator.GetLayerWeight(i); 102 | if (i == 0) 103 | layerWeight = 1; 104 | 105 | var stateInfo = animator.GetCurrentAnimatorStateInfo(i); 106 | var nextStateInfo = animator.GetNextAnimatorStateInfo(i); 107 | 108 | #if UNITY_5 109 | var clipInfo = animator.GetCurrentAnimatorClipInfo(i); 110 | var nextClipInfo = animator.GetNextAnimatorClipInfo(i); 111 | #else 112 | var clipInfo = animator.GetCurrentAnimatorClipInfo(i); 113 | var nextClipInfo = animator.GetNextAnimatorClipInfo(i); 114 | #endif 115 | MixMode mode = layerMixModes[i]; 116 | 117 | if (mode == MixMode.AlwaysMix) { 118 | //always use Mix instead of Applying the first non-zero weighted clip 119 | foreach (var info in clipInfo) { 120 | float weight = info.weight * layerWeight; 121 | if (weight == 0) 122 | continue; 123 | 124 | float time = stateInfo.normalizedTime * info.clip.length; 125 | animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight); 126 | } 127 | 128 | foreach (var info in nextClipInfo) { 129 | float weight = info.weight * layerWeight; 130 | if (weight == 0) 131 | continue; 132 | 133 | float time = nextStateInfo.normalizedTime * info.clip.length; 134 | animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight); 135 | } 136 | } else if (mode >= MixMode.MixNext) { 137 | //apply first non-zero weighted clip 138 | int c = 0; 139 | 140 | for (; c < clipInfo.Length; c++) { 141 | var info = clipInfo[c]; 142 | float weight = info.weight * layerWeight; 143 | if (weight == 0) 144 | continue; 145 | 146 | float time = stateInfo.normalizedTime * info.clip.length; 147 | animationTable[info.clip.name].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null); 148 | break; 149 | } 150 | 151 | //mix the rest 152 | for (; c < clipInfo.Length; c++) { 153 | var info = clipInfo[c]; 154 | float weight = info.weight * layerWeight; 155 | if (weight == 0) 156 | continue; 157 | 158 | float time = stateInfo.normalizedTime * info.clip.length; 159 | animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight); 160 | } 161 | 162 | c = 0; 163 | 164 | //apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights) 165 | if (mode == MixMode.SpineStyle) { 166 | for (; c < nextClipInfo.Length; c++) { 167 | var info = nextClipInfo[c]; 168 | float weight = info.weight * layerWeight; 169 | if (weight == 0) 170 | continue; 171 | 172 | float time = nextStateInfo.normalizedTime * info.clip.length; 173 | animationTable[info.clip.name].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null); 174 | break; 175 | } 176 | } 177 | 178 | //mix the rest 179 | for (; c < nextClipInfo.Length; c++) { 180 | var info = nextClipInfo[c]; 181 | float weight = info.weight * layerWeight; 182 | if (weight == 0) 183 | continue; 184 | 185 | float time = nextStateInfo.normalizedTime * info.clip.length; 186 | animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight); 187 | } 188 | } 189 | } 190 | 191 | if (_UpdateLocal != null) 192 | _UpdateLocal(this); 193 | 194 | skeleton.UpdateWorldTransform(); 195 | 196 | if (_UpdateWorld != null) { 197 | _UpdateWorld(this); 198 | skeleton.UpdateWorldTransform(); 199 | } 200 | 201 | if (_UpdateComplete != null) { 202 | _UpdateComplete(this); 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /spine-unity/SkeletonDataAsset.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.IO; 33 | using System.Collections.Generic; 34 | using UnityEngine; 35 | using Spine; 36 | 37 | public class SkeletonDataAsset : ScriptableObject { 38 | public AtlasAsset[] atlasAssets; 39 | #if SPINE_TK2D 40 | public tk2dSpriteCollectionData spriteCollection; 41 | #endif 42 | public TextAsset skeletonJSON; 43 | public float scale = 1; 44 | public String[] fromAnimation; 45 | public String[] toAnimation; 46 | public float[] duration; 47 | public float defaultMix; 48 | public RuntimeAnimatorController controller; 49 | private SkeletonData skeletonData; 50 | private AnimationStateData stateData; 51 | 52 | public void Reset() { 53 | skeletonData = null; 54 | stateData = null; 55 | } 56 | 57 | public SkeletonData GetSkeletonData(bool quiet) { 58 | if (atlasAssets == null) { 59 | atlasAssets = new AtlasAsset[0]; 60 | if (!quiet) 61 | Debug.LogError("Atlas not set for SkeletonData asset: " + name, this); 62 | Reset(); 63 | return null; 64 | } 65 | 66 | if (skeletonJSON == null) { 67 | if (!quiet) 68 | Debug.LogError("Skeleton JSON file not set for SkeletonData asset: " + name, this); 69 | Reset(); 70 | return null; 71 | } 72 | 73 | #if !SPINE_TK2D 74 | if (atlasAssets.Length == 0) { 75 | Reset(); 76 | return null; 77 | } 78 | #else 79 | if (atlasAssets.Length == 0 && spriteCollection == null) { 80 | Reset(); 81 | return null; 82 | } 83 | #endif 84 | 85 | Atlas[] atlasArr = new Atlas[atlasAssets.Length]; 86 | for (int i = 0; i < atlasAssets.Length; i++) { 87 | if (atlasAssets[i] == null) { 88 | Reset(); 89 | return null; 90 | } 91 | atlasArr[i] = atlasAssets[i].GetAtlas(); 92 | if (atlasArr[i] == null) { 93 | Reset(); 94 | return null; 95 | } 96 | } 97 | 98 | if (skeletonData != null) 99 | return skeletonData; 100 | 101 | AttachmentLoader attachmentLoader; 102 | float skeletonDataScale; 103 | 104 | #if !SPINE_TK2D 105 | attachmentLoader = new AtlasAttachmentLoader(atlasArr); 106 | skeletonDataScale = scale; 107 | #else 108 | if (spriteCollection != null) { 109 | attachmentLoader = new SpriteCollectionAttachmentLoader(spriteCollection) 110 | skeletonDataScale = (1.0f / (spriteCollection.invOrthoSize * spriteCollection.halfTargetHeight) * scale) * 100f; 111 | } else { 112 | if (atlasArr.Length == 0) { 113 | Reset(); 114 | if (!quiet) Debug.LogError("Atlas not set for SkeletonData asset: " + name, this); 115 | return null; 116 | } 117 | attachmentLoader = new AtlasAttachmentLoader(atlasArr); 118 | skeletonDataScale = scale; 119 | } 120 | #endif 121 | 122 | try 123 | { 124 | var skeletonName = skeletonJSON.name; 125 | 126 | 127 | 128 | if (skeletonData == null) 129 | { 130 | if (skeletonName.Contains(".skel")) 131 | { 132 | var input = new MemoryStream(skeletonJSON.bytes); 133 | var binary = new SkeletonBinary(attachmentLoader); 134 | binary.Scale = skeletonDataScale; 135 | 136 | #if UNITY_EDITOR 137 | if (!Application.isPlaying) 138 | { 139 | binary.CacheStrings = new List() { null, "" }; 140 | binary.CacheOffsetVertices = new List(); 141 | } 142 | #endif 143 | 144 | skeletonData = binary.ReadSkeletonData(input); 145 | 146 | 147 | #if UNITY_EDITOR 148 | if (skeletonData.version != "HuaHua2.0") 149 | { 150 | Debug.LogError($"Exist unconverted spine:{skeletonName} size:{input.Length}"); 151 | } 152 | 153 | if (!Application.isPlaying && skeletonData.version != "HuaHua2.0") 154 | { 155 | //HuaHua 156 | var output = new MemoryStream(); 157 | binary.WriteSkeletonData(output, skeletonData); 158 | var path = UnityEditor.AssetDatabase.GetAssetPath(this); 159 | path = path.Replace("_SkeletonData.asset", ".skel.bytes"); 160 | File.WriteAllBytes(path, output.ToArray()); 161 | } 162 | #endif 163 | } 164 | else 165 | { 166 | Debug.LogError($"Spine don't use json == {skeletonName}"); //HuaHua 167 | var input = new StringReader(skeletonJSON.text); 168 | var json = new SkeletonJson(attachmentLoader); 169 | json.Scale = skeletonDataScale; 170 | skeletonData = json.ReadSkeletonData(input); 171 | 172 | #if UNITY_EDITOR 173 | if (!Application.isPlaying) 174 | { 175 | //HuaHua 176 | var output = new MemoryStream(); 177 | var binary = new SkeletonBinary(attachmentLoader); 178 | binary.Scale = skeletonDataScale; 179 | binary.WriteSkeletonData(output, skeletonData); 180 | var path = UnityEditor.AssetDatabase.GetAssetPath(this); 181 | path = path.Replace("_SkeletonData.asset", ".skel.bytes"); 182 | File.WriteAllBytes(path, output.ToArray()); 183 | } 184 | #endif 185 | } 186 | } 187 | 188 | } catch (Exception ex) { 189 | if (!quiet) 190 | Debug.LogError("Error reading skeleton file for SkeletonData asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this); 191 | return null; 192 | } 193 | 194 | stateData = new AnimationStateData(skeletonData); 195 | FillStateData(); 196 | 197 | return skeletonData; 198 | } 199 | 200 | public void FillStateData () { 201 | if (stateData == null) 202 | return; 203 | 204 | stateData.DefaultMix = defaultMix; 205 | for (int i = 0, n = fromAnimation.Length; i < n; i++) { 206 | if (fromAnimation[i].Length == 0 || toAnimation[i].Length == 0) 207 | continue; 208 | stateData.SetMix(fromAnimation[i], toAnimation[i], duration[i]); 209 | } 210 | } 211 | 212 | public AnimationStateData GetAnimationStateData() { 213 | if (stateData != null) 214 | return stateData; 215 | GetSkeletonData(false); 216 | return stateData; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /spine-unity/SkeletonExtensions.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | /***************************************************************************** 32 | * Spine Extensions created by Mitch Thompson 33 | * Full irrevocable rights and permissions granted to Esoteric Software 34 | *****************************************************************************/ 35 | 36 | using UnityEngine; 37 | using System.Collections; 38 | using Spine; 39 | 40 | public static class SkeletonExtensions { 41 | 42 | public static void SetColor (this Skeleton skeleton, Color color) { 43 | skeleton.A = color.a; 44 | skeleton.R = color.r; 45 | skeleton.G = color.g; 46 | skeleton.B = color.b; 47 | } 48 | 49 | public static void SetColor (this Skeleton skeleton, Color32 color) { 50 | skeleton.A = color.a / 255f; 51 | skeleton.R = color.r / 255f; 52 | skeleton.G = color.g / 255f; 53 | skeleton.B = color.b / 255f; 54 | } 55 | 56 | public static void SetColor (this Slot slot, Color color) { 57 | slot.A = color.a; 58 | slot.R = color.r; 59 | slot.G = color.g; 60 | slot.B = color.b; 61 | } 62 | 63 | public static void SetColor (this Slot slot, Color32 color) { 64 | slot.A = color.a / 255f; 65 | slot.R = color.r / 255f; 66 | slot.G = color.g / 255f; 67 | slot.B = color.b / 255f; 68 | } 69 | 70 | public static void SetColor (this RegionAttachment attachment, Color color) { 71 | attachment.A = color.a; 72 | attachment.R = color.r; 73 | attachment.G = color.g; 74 | attachment.B = color.b; 75 | } 76 | 77 | public static void SetColor (this RegionAttachment attachment, Color32 color) { 78 | attachment.A = color.a / 255f; 79 | attachment.R = color.r / 255f; 80 | attachment.G = color.g / 255f; 81 | attachment.B = color.b / 255f; 82 | } 83 | 84 | public static void SetColor (this MeshAttachment attachment, Color color) { 85 | attachment.A = color.a; 86 | attachment.R = color.r; 87 | attachment.G = color.g; 88 | attachment.B = color.b; 89 | } 90 | 91 | public static void SetColor (this MeshAttachment attachment, Color32 color) { 92 | attachment.A = color.a / 255f; 93 | attachment.R = color.r / 255f; 94 | attachment.G = color.g / 255f; 95 | attachment.B = color.b / 255f; 96 | } 97 | 98 | public static void SetColor (this SkinnedMeshAttachment attachment, Color color) { 99 | attachment.A = color.a; 100 | attachment.R = color.r; 101 | attachment.G = color.g; 102 | attachment.B = color.b; 103 | } 104 | 105 | public static void SetColor (this SkinnedMeshAttachment attachment, Color32 color) { 106 | attachment.A = color.a / 255f; 107 | attachment.R = color.r / 255f; 108 | attachment.G = color.g / 255f; 109 | attachment.B = color.b / 255f; 110 | } 111 | 112 | public static void SetPosition (this Bone bone, Vector2 position) { 113 | bone.X = position.x; 114 | bone.Y = position.y; 115 | } 116 | 117 | public static void SetPosition (this Bone bone, Vector3 position) { 118 | bone.X = position.x; 119 | bone.Y = position.y; 120 | } 121 | 122 | public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton") { 123 | var att = sprite.ToRegionAttachment(shaderName); 124 | skeleton.FindSlot(slotName).Attachment = att; 125 | 126 | return att; 127 | } 128 | 129 | public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton") { 130 | var att = sprite.ToRegionAttachment(shaderName); 131 | 132 | var slotIndex = skeletonData.FindSlotIndex(slotName); 133 | Skin skin = skeletonData.defaultSkin; 134 | if (skinName != "") 135 | skin = skeletonData.FindSkin(skinName); 136 | 137 | skin.AddAttachment(slotIndex, att.Name, att); 138 | 139 | return att; 140 | } 141 | 142 | public static RegionAttachment ToRegionAttachment (this Sprite sprite, string shaderName = "Spine/Skeleton") { 143 | var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); 144 | var att = loader.NewRegionAttachment(null, sprite.name, ""); 145 | loader = null; 146 | return att; 147 | } 148 | } -------------------------------------------------------------------------------- /spine-unity/SkeletonUtility/Editor/SkeletonUtilitySubmeshRendererInspector.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System; 4 | using System.Collections; 5 | using System.Reflection; 6 | 7 | [CustomEditor(typeof(SkeletonUtilitySubmeshRenderer))] 8 | public class SkeletonUtilitySubmeshRendererInspector : Editor { 9 | 10 | private static MethodInfo EditorGUILayoutSortingLayerField; 11 | protected SerializedObject rendererSerializedObject; 12 | protected SerializedProperty sortingLayerIDProperty; 13 | 14 | SkeletonUtilitySubmeshRenderer component; 15 | 16 | void OnEnable () { 17 | component = (SkeletonUtilitySubmeshRenderer)target; 18 | 19 | if (EditorGUILayoutSortingLayerField == null) 20 | EditorGUILayoutSortingLayerField = typeof(EditorGUILayout).GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle) }, null); 21 | 22 | rendererSerializedObject = new SerializedObject(((SkeletonUtilitySubmeshRenderer)target).GetComponent()); 23 | sortingLayerIDProperty = rendererSerializedObject.FindProperty("m_SortingLayerID"); 24 | } 25 | 26 | public override void OnInspectorGUI () { 27 | // Sorting Layers 28 | { 29 | var renderer = component.GetComponent(); 30 | if (renderer != null) { 31 | EditorGUI.BeginChangeCheck(); 32 | 33 | if (EditorGUILayoutSortingLayerField != null && sortingLayerIDProperty != null) { 34 | EditorGUILayoutSortingLayerField.Invoke(null, new object[] { new GUIContent("Sorting Layer"), sortingLayerIDProperty, EditorStyles.popup }); 35 | } else { 36 | renderer.sortingLayerID = EditorGUILayout.IntField("Sorting Layer ID", renderer.sortingLayerID); 37 | } 38 | 39 | renderer.sortingOrder = EditorGUILayout.IntField("Order in Layer", renderer.sortingOrder); 40 | 41 | if (EditorGUI.EndChangeCheck()) { 42 | rendererSerializedObject.ApplyModifiedProperties(); 43 | EditorUtility.SetDirty(renderer); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | [RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] 5 | 6 | public abstract class SkeletonUtilityConstraint : MonoBehaviour { 7 | 8 | protected SkeletonUtilityBone utilBone; 9 | protected SkeletonUtility skeletonUtility; 10 | 11 | protected virtual void OnEnable () { 12 | utilBone = GetComponent(); 13 | skeletonUtility = SkeletonUtility.GetInParent(transform); 14 | skeletonUtility.RegisterConstraint(this); 15 | } 16 | 17 | protected virtual void OnDisable () { 18 | skeletonUtility.UnregisterConstraint(this); 19 | } 20 | 21 | public abstract void DoUpdate (); 22 | } 23 | -------------------------------------------------------------------------------- /spine-unity/SkeletonUtility/SkeletonUtilityEyeConstraint.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class SkeletonUtilityEyeConstraint : SkeletonUtilityConstraint { 5 | 6 | public Transform[] eyes; 7 | public float radius = 0.5f; 8 | public Transform target; 9 | public Vector3 targetPosition; 10 | public float speed = 10; 11 | Vector3[] origins; 12 | Vector3 centerPoint; 13 | 14 | protected override void OnEnable () { 15 | if (!Application.isPlaying) 16 | return; 17 | 18 | base.OnEnable(); 19 | 20 | Bounds centerBounds = new Bounds(eyes[0].localPosition, Vector3.zero); 21 | origins = new Vector3[eyes.Length]; 22 | for (int i = 0; i < eyes.Length; i++) { 23 | origins[i] = eyes[i].localPosition; 24 | centerBounds.Encapsulate(origins[i]); 25 | } 26 | 27 | centerPoint = centerBounds.center; 28 | } 29 | 30 | protected override void OnDisable () { 31 | if (!Application.isPlaying) 32 | return; 33 | 34 | base.OnDisable(); 35 | } 36 | 37 | public override void DoUpdate () { 38 | 39 | if (target != null) 40 | targetPosition = target.position; 41 | 42 | Vector3 goal = targetPosition; 43 | 44 | Vector3 center = transform.TransformPoint(centerPoint); 45 | Vector3 dir = goal - center; 46 | 47 | if (dir.magnitude > 1) 48 | dir.Normalize(); 49 | 50 | for (int i = 0; i < eyes.Length; i++) { 51 | center = transform.TransformPoint(origins[i]); 52 | eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius), speed * Time.deltaTime); 53 | } 54 | 55 | } 56 | } -------------------------------------------------------------------------------- /spine-unity/SkeletonUtility/SkeletonUtilityGroundConstraint.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | [RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] 5 | public class SkeletonUtilityGroundConstraint : SkeletonUtilityConstraint { 6 | 7 | #if UNITY_4_3 8 | public LayerMask groundMask; 9 | public bool use2D = false; 10 | public bool useRadius = false; 11 | public float castRadius = 0.1f; 12 | public float castDistance = 5f; 13 | public float castOffset = 0; 14 | public float groundOffset = 0; 15 | public float adjustSpeed = 5; 16 | #else 17 | [Tooltip("LayerMask for what objects to raycast against")] 18 | public LayerMask groundMask; 19 | [Tooltip("The 2D")] 20 | public bool use2D = false; 21 | [Tooltip("Uses SphereCast for 3D mode and CircleCast for 2D mode")] 22 | public bool useRadius = false; 23 | [Tooltip("The Radius")] 24 | public float castRadius = 0.1f; 25 | [Tooltip("How high above the target bone to begin casting from")] 26 | public float castDistance = 5f; 27 | [Tooltip("X-Axis adjustment")] 28 | public float castOffset = 0; 29 | [Tooltip("Y-Axis adjustment")] 30 | public float groundOffset = 0; 31 | [Tooltip("How fast the target IK position adjusts to the ground. Use smaller values to prevent snapping")] 32 | public float adjustSpeed = 5; 33 | #endif 34 | 35 | 36 | Vector3 rayOrigin; 37 | Vector3 rayDir = new Vector3(0, -1, 0); 38 | float hitY; 39 | float lastHitY; 40 | 41 | protected override void OnEnable () { 42 | base.OnEnable(); 43 | } 44 | 45 | protected override void OnDisable () { 46 | base.OnDisable(); 47 | } 48 | 49 | public override void DoUpdate () { 50 | rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0); 51 | 52 | hitY = float.MinValue; 53 | if (use2D) { 54 | RaycastHit2D hit; 55 | 56 | if (useRadius) { 57 | #if UNITY_4_3 58 | //NOTE: Unity 4.3.x does not have CircleCast 59 | hit = Physics2D.Raycast(rayOrigin , rayDir, castDistance + groundOffset, groundMask); 60 | #else 61 | hit = Physics2D.CircleCast(rayOrigin, castRadius, rayDir, castDistance + groundOffset, groundMask); 62 | #endif 63 | } else { 64 | hit = Physics2D.Raycast(rayOrigin, rayDir, castDistance + groundOffset, groundMask); 65 | } 66 | 67 | if (hit.collider != null) { 68 | hitY = hit.point.y + groundOffset; 69 | if (Application.isPlaying) { 70 | hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); 71 | } 72 | } else { 73 | if (Application.isPlaying) 74 | hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); 75 | } 76 | } else { 77 | RaycastHit hit; 78 | bool validHit = false; 79 | 80 | if (useRadius) { 81 | validHit = Physics.SphereCast(rayOrigin, castRadius, rayDir, out hit, castDistance + groundOffset, groundMask); 82 | } else { 83 | validHit = Physics.Raycast(rayOrigin, rayDir, out hit, castDistance + groundOffset, groundMask); 84 | } 85 | 86 | if (validHit) { 87 | hitY = hit.point.y + groundOffset; 88 | if (Application.isPlaying) { 89 | hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); 90 | } 91 | } else { 92 | if (Application.isPlaying) 93 | hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); 94 | } 95 | } 96 | 97 | Vector3 v = transform.position; 98 | v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue); 99 | transform.position = v; 100 | 101 | utilBone.bone.X = transform.localPosition.x; 102 | utilBone.bone.Y = transform.localPosition.y; 103 | 104 | lastHitY = hitY; 105 | } 106 | 107 | void OnDrawGizmos () { 108 | Vector3 hitEnd = rayOrigin + (rayDir * Mathf.Min(castDistance, rayOrigin.y - hitY)); 109 | Vector3 clearEnd = rayOrigin + (rayDir * castDistance); 110 | Gizmos.DrawLine(rayOrigin, hitEnd); 111 | 112 | if (useRadius) { 113 | Gizmos.DrawLine(new Vector3(hitEnd.x - castRadius, hitEnd.y - groundOffset, hitEnd.z), new Vector3(hitEnd.x + castRadius, hitEnd.y - groundOffset, hitEnd.z)); 114 | Gizmos.DrawLine(new Vector3(clearEnd.x - castRadius, clearEnd.y, clearEnd.z), new Vector3(clearEnd.x + castRadius, clearEnd.y, clearEnd.z)); 115 | } 116 | 117 | Gizmos.color = Color.red; 118 | Gizmos.DrawLine(hitEnd, clearEnd); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class SkeletonUtilityKinematicShadow : MonoBehaviour { 6 | public bool hideShadow = true; 7 | public Transform parent; 8 | Dictionary shadowTable; 9 | GameObject shadowRoot; 10 | 11 | void Start () { 12 | shadowRoot = (GameObject)Instantiate(gameObject); 13 | if (hideShadow) 14 | shadowRoot.hideFlags = HideFlags.HideInHierarchy; 15 | 16 | if(parent == null) 17 | shadowRoot.transform.parent = transform.root; 18 | else 19 | shadowRoot.transform.parent = parent; 20 | 21 | shadowTable = new Dictionary(); 22 | 23 | Destroy(shadowRoot.GetComponent()); 24 | 25 | shadowRoot.transform.position = transform.position; 26 | shadowRoot.transform.rotation = transform.rotation; 27 | 28 | Vector3 scaleRef = transform.TransformPoint(Vector3.right); 29 | float scale = Vector3.Distance(transform.position, scaleRef); 30 | shadowRoot.transform.localScale = Vector3.one; 31 | 32 | var shadowJoints = shadowRoot.GetComponentsInChildren(); 33 | foreach (Joint j in shadowJoints) { 34 | j.connectedAnchor *= scale; 35 | } 36 | 37 | var joints = GetComponentsInChildren(); 38 | foreach (var j in joints) 39 | Destroy(j); 40 | 41 | var rbs = GetComponentsInChildren(); 42 | foreach (var rb in rbs) 43 | Destroy(rb); 44 | 45 | var colliders = GetComponentsInChildren(); 46 | foreach (var c in colliders) 47 | Destroy(c); 48 | 49 | 50 | //match by bone name 51 | var shadowBones = shadowRoot.GetComponentsInChildren(); 52 | var bones = GetComponentsInChildren(); 53 | 54 | //build bone lookup 55 | foreach (var b in bones) { 56 | if (b.gameObject == gameObject) 57 | continue; 58 | 59 | foreach (var sb in shadowBones) { 60 | if (sb.GetComponent() == null) 61 | continue; 62 | 63 | if (sb.boneName == b.boneName) { 64 | shadowTable.Add(sb.transform, b.transform); 65 | break; 66 | } 67 | } 68 | } 69 | 70 | foreach (var b in shadowBones) 71 | Destroy(b); 72 | } 73 | 74 | void FixedUpdate () { 75 | shadowRoot.GetComponent().MovePosition(transform.position); 76 | shadowRoot.GetComponent().MoveRotation(transform.rotation); 77 | 78 | foreach (var pair in shadowTable) { 79 | pair.Value.localPosition = pair.Key.localPosition; 80 | pair.Value.localRotation = pair.Key.localRotation; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | [ExecuteInEditMode] 5 | public class SkeletonUtilitySubmeshRenderer : MonoBehaviour { 6 | [System.NonSerialized] 7 | public Mesh mesh; 8 | public int submeshIndex = 0; 9 | public Material hiddenPassMaterial; 10 | Renderer cachedRenderer; 11 | MeshFilter filter; 12 | Material[] sharedMaterials; 13 | 14 | void Awake () { 15 | cachedRenderer = GetComponent(); 16 | filter = GetComponent(); 17 | sharedMaterials = new Material[0]; 18 | } 19 | 20 | public void SetMesh (Renderer parentRenderer, Mesh mesh, Material mat) { 21 | if (cachedRenderer == null) 22 | return; 23 | 24 | cachedRenderer.enabled = true; 25 | filter.sharedMesh = mesh; 26 | if (cachedRenderer.sharedMaterials.Length != parentRenderer.sharedMaterials.Length) { 27 | sharedMaterials = parentRenderer.sharedMaterials; 28 | } 29 | 30 | for (int i = 0; i < sharedMaterials.Length; i++) { 31 | if (i == submeshIndex) 32 | sharedMaterials[i] = mat; 33 | else 34 | sharedMaterials[i] = hiddenPassMaterial; 35 | } 36 | 37 | cachedRenderer.sharedMaterials = sharedMaterials; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /spine-unity/SpineAttributes.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | /***************************************************************************** 32 | * Spine Attributes created by Mitch Thompson 33 | * Full irrevocable rights and permissions granted to Esoteric Software 34 | *****************************************************************************/ 35 | using UnityEngine; 36 | using System.Collections; 37 | 38 | public class SpineSlot : PropertyAttribute { 39 | public string startsWith = ""; 40 | public string dataField = ""; 41 | 42 | /// 43 | /// Smart popup menu for Spine Slots 44 | /// 45 | /// Filters popup results to elements that begin with supplied string. 46 | /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. 47 | /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives). 48 | /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. 49 | /// 50 | public SpineSlot(string startsWith = "", string dataField = "") { 51 | this.startsWith = startsWith; 52 | this.dataField = dataField; 53 | } 54 | } 55 | 56 | public class SpineSkin : PropertyAttribute { 57 | public string startsWith = ""; 58 | public string dataField = ""; 59 | 60 | /// 61 | /// Smart popup menu for Spine Skins 62 | /// 63 | /// Filters popup results to elements that begin with supplied string. 64 | /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. 65 | /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) 66 | /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. 67 | /// 68 | public SpineSkin(string startsWith = "", string dataField = "") { 69 | this.startsWith = startsWith; 70 | this.dataField = dataField; 71 | } 72 | } 73 | public class SpineAnimation : PropertyAttribute { 74 | public string startsWith = ""; 75 | public string dataField = ""; 76 | 77 | /// 78 | /// Smart popup menu for Spine Animations 79 | /// 80 | /// Filters popup results to elements that begin with supplied string. 81 | /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. 82 | /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) 83 | /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. 84 | /// 85 | public SpineAnimation(string startsWith = "", string dataField = "") { 86 | this.startsWith = startsWith; 87 | this.dataField = dataField; 88 | } 89 | } 90 | 91 | public class SpineAttachment : PropertyAttribute { 92 | public bool returnAttachmentPath = false; 93 | public bool currentSkinOnly = false; 94 | public bool placeholdersOnly = false; 95 | public string dataField = ""; 96 | public string slotField = ""; 97 | 98 | 99 | public SpineAttachment() { 100 | 101 | } 102 | 103 | /// 104 | /// Smart popup menu for Spine Attachments 105 | /// 106 | /// Filters popup results to only include the current Skin. Only valid when a SkeletonRenderer is the data source. 107 | /// Returns a fully qualified path for an Attachment in the format "Skin/Slot/AttachmentName" 108 | /// Filters popup results to exclude attachments that are not children of Skin Placeholders 109 | /// If specified, a locally scoped field with the name supplied by in slotField will be used to limit the popup results to children of a named slot 110 | /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. 111 | /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) 112 | /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. 113 | /// 114 | public SpineAttachment(bool currentSkinOnly = true, bool returnAttachmentPath = false, bool placeholdersOnly = false, string slotField = "", string dataField = "") { 115 | this.currentSkinOnly = currentSkinOnly; 116 | this.returnAttachmentPath = returnAttachmentPath; 117 | this.placeholdersOnly = placeholdersOnly; 118 | this.slotField = slotField; 119 | this.dataField = dataField; 120 | } 121 | 122 | public static Hierarchy GetHierarchy(string fullPath) { 123 | return new Hierarchy(fullPath); 124 | } 125 | 126 | public static Spine.Attachment GetAttachment(string attachmentPath, Spine.SkeletonData skeletonData) { 127 | var hierarchy = SpineAttachment.GetHierarchy(attachmentPath); 128 | if (hierarchy.name == "") 129 | return null; 130 | 131 | return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name); 132 | } 133 | 134 | public static Spine.Attachment GetAttachment(string attachmentPath, SkeletonDataAsset skeletonDataAsset) { 135 | return GetAttachment(attachmentPath, skeletonDataAsset.GetSkeletonData(true)); 136 | } 137 | 138 | public struct Hierarchy { 139 | public string skin; 140 | public string slot; 141 | public string name; 142 | 143 | public Hierarchy(string fullPath) { 144 | string[] chunks = fullPath.Split(new char[]{'/'}, System.StringSplitOptions.RemoveEmptyEntries); 145 | if (chunks.Length == 0) { 146 | skin = ""; 147 | slot = ""; 148 | name = ""; 149 | return; 150 | } 151 | else if (chunks.Length < 2) { 152 | throw new System.Exception("Cannot generate Attachment Hierarchy from string! Not enough components! [" + fullPath + "]"); 153 | } 154 | skin = chunks[0]; 155 | slot = chunks[1]; 156 | name = ""; 157 | for (int i = 2; i < chunks.Length; i++) { 158 | name += chunks[i]; 159 | } 160 | } 161 | } 162 | } 163 | 164 | public class SpineBone : PropertyAttribute { 165 | public string startsWith = ""; 166 | public string dataField = ""; 167 | 168 | /// 169 | /// Smart popup menu for Spine Bones 170 | /// 171 | /// Filters popup results to elements that begin with supplied string. 172 | /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. 173 | /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) 174 | /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. 175 | /// 176 | public SpineBone(string startsWith = "", string dataField = "") { 177 | this.startsWith = startsWith; 178 | this.dataField = dataField; 179 | } 180 | 181 | public static Spine.Bone GetBone(string boneName, SkeletonRenderer renderer) { 182 | if (renderer.skeleton == null) 183 | return null; 184 | 185 | return renderer.skeleton.FindBone(boneName); 186 | } 187 | 188 | public static Spine.BoneData GetBoneData(string boneName, SkeletonDataAsset skeletonDataAsset) { 189 | var data = skeletonDataAsset.GetSkeletonData(true); 190 | 191 | return data.FindBone(boneName); 192 | } 193 | } 194 | 195 | public class SpineAtlasRegion : PropertyAttribute { 196 | //TODO: Standardize with Skeleton attributes 197 | //NOTE: For now, relies on locally scoped field named "atlasAsset" for source. 198 | } -------------------------------------------------------------------------------- /spine-unity/SpriteAttacher.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Spine; 5 | 6 | public class SpriteAttacher : MonoBehaviour { 7 | 8 | 9 | public bool attachOnStart = true; 10 | public bool keepLoaderInMemory = true; 11 | 12 | public Sprite sprite; 13 | 14 | [SpineSlot] 15 | public string slot; 16 | 17 | private SpriteAttachmentLoader loader; 18 | private RegionAttachment attachment; 19 | 20 | void Start () { 21 | if (attachOnStart) 22 | Attach(); 23 | } 24 | 25 | public void Attach () { 26 | var skeletonRenderer = GetComponent(); 27 | 28 | if (loader == null) 29 | //create loader instance, tell it what sprite and shader to use 30 | loader = new SpriteAttachmentLoader(sprite, Shader.Find("Spine/Skeleton")); 31 | 32 | if (attachment == null) 33 | attachment = loader.NewRegionAttachment(null, sprite.name, ""); 34 | 35 | skeletonRenderer.skeleton.FindSlot(slot).Attachment = attachment; 36 | 37 | if (!keepLoaderInMemory) 38 | loader = null; 39 | } 40 | } 41 | 42 | public class SpriteAttachmentLoader : AttachmentLoader { 43 | 44 | //TODO: Memory cleanup functions 45 | 46 | //IMPORTANT: Make sure you clear this when you don't need it anymore. Goodluck. 47 | public static Dictionary atlasTable = new Dictionary(); 48 | 49 | //Shouldn't need to clear this, should just prevent redoing premultiply alpha pass on packed atlases 50 | public static List premultipliedAtlasIds = new List(); 51 | 52 | Sprite sprite; 53 | Shader shader; 54 | 55 | public SpriteAttachmentLoader (Sprite sprite, Shader shader) { 56 | 57 | if (sprite.packed && sprite.packingMode == SpritePackingMode.Tight) { 58 | Debug.LogError("Tight Packer Policy not supported yet!"); 59 | return; 60 | } 61 | 62 | this.sprite = sprite; 63 | this.shader = shader; 64 | 65 | Texture2D tex = sprite.texture; 66 | //premultiply texture if it hasn't been yet 67 | int instanceId = tex.GetInstanceID(); 68 | if (!premultipliedAtlasIds.Contains(instanceId)) { 69 | try { 70 | var colors = tex.GetPixels(); 71 | Color c; 72 | float a; 73 | for (int i = 0; i < colors.Length; i++) { 74 | c = colors[i]; 75 | a = c.a; 76 | c.r *= a; 77 | c.g *= a; 78 | c.b *= a; 79 | colors[i] = c; 80 | } 81 | 82 | tex.SetPixels(colors); 83 | tex.Apply(); 84 | 85 | premultipliedAtlasIds.Add(instanceId); 86 | } catch { 87 | //texture is not readable! Can't pre-multiply it, you're on your own. 88 | } 89 | } 90 | } 91 | 92 | public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) { 93 | RegionAttachment attachment = new RegionAttachment(name); 94 | 95 | Texture2D tex = sprite.texture; 96 | int instanceId = tex.GetInstanceID(); 97 | AtlasRegion atlasRegion; 98 | 99 | //check cache first 100 | if (atlasTable.ContainsKey(instanceId)) { 101 | atlasRegion = atlasTable[instanceId]; 102 | } else { 103 | //Setup new material 104 | Material mat = new Material(shader); 105 | if (sprite.packed) 106 | mat.name = "Unity Packed Sprite Material"; 107 | else 108 | mat.name = sprite.name + " Sprite Material"; 109 | mat.mainTexture = tex; 110 | 111 | //create faux-region to play nice with SkeletonRenderer 112 | atlasRegion = new AtlasRegion(); 113 | AtlasPage page = new AtlasPage(); 114 | page.rendererObject = mat; 115 | atlasRegion.page = page; 116 | 117 | //cache it 118 | atlasTable[instanceId] = atlasRegion; 119 | } 120 | 121 | Rect texRect = sprite.textureRect; 122 | 123 | //normalize rect to UV space of packed atlas 124 | texRect.x = Mathf.InverseLerp(0, tex.width, texRect.x); 125 | texRect.y = Mathf.InverseLerp(0, tex.height, texRect.y); 126 | texRect.width = Mathf.InverseLerp(0, tex.width, texRect.width); 127 | texRect.height = Mathf.InverseLerp(0, tex.height, texRect.height); 128 | 129 | Bounds bounds = sprite.bounds; 130 | Vector3 size = bounds.size; 131 | 132 | //TODO: make sure this rotation thing actually works 133 | bool rotated = false; 134 | if (sprite.packed) 135 | rotated = sprite.packingRotation == SpritePackingRotation.Any; 136 | 137 | //do some math and assign UVs and sizes 138 | attachment.SetUVs(texRect.xMin, texRect.yMax, texRect.xMax, texRect.yMin, rotated); 139 | attachment.RendererObject = atlasRegion; 140 | attachment.SetColor(Color.white); 141 | attachment.ScaleX = 1; 142 | attachment.ScaleY = 1; 143 | attachment.RegionOffsetX = sprite.rect.width * (0.5f - Mathf.InverseLerp(bounds.min.x, bounds.max.x, 0)) / sprite.pixelsPerUnit; 144 | attachment.RegionOffsetY = sprite.rect.height * (0.5f - Mathf.InverseLerp(bounds.min.y, bounds.max.y, 0)) / sprite.pixelsPerUnit; 145 | attachment.Width = size.x; 146 | attachment.Height = size.y; 147 | attachment.RegionWidth = size.x; 148 | attachment.RegionHeight = size.y; 149 | attachment.RegionOriginalWidth = size.x; 150 | attachment.RegionOriginalHeight = size.y; 151 | attachment.UpdateOffset(); 152 | 153 | return attachment; 154 | } 155 | 156 | public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) { 157 | //TODO: Unity 5 only 158 | throw new System.NotImplementedException(); 159 | } 160 | 161 | public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, string name, string path) { 162 | throw new System.NotImplementedException(); 163 | } 164 | 165 | public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) { 166 | throw new System.NotImplementedException(); 167 | } 168 | } -------------------------------------------------------------------------------- /spine-unity/SpriteCollectionAttachmentLoader.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License 3 | * Version 2.1 4 | * 5 | * Copyright (c) 2013, Esoteric Software 6 | * All rights reserved. 7 | * 8 | * You are granted a perpetual, non-exclusive, non-sublicensable and 9 | * non-transferable license to install, execute and perform the Spine Runtimes 10 | * Software (the "Software") solely for internal use. Without the written 11 | * permission of Esoteric Software (typically granted by licensing Spine), you 12 | * may not (a) modify, translate, adapt or otherwise create derivative works, 13 | * improvements of the Software or develop new applications using the Software 14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright, 15 | * trademark, patent or other intellectual property or proprietary rights 16 | * notices on or in the Software, including any copy thereof. Redistributions 17 | * in binary or source form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | #if SPINE_TK2D 32 | using System; 33 | using UnityEngine; 34 | using Spine; 35 | 36 | // TODO: handle TPackerCW flip mode (probably not swap uv horizontaly) 37 | 38 | public class SpriteCollectionAttachmentLoader : AttachmentLoader { 39 | private tk2dSpriteCollectionData sprites; 40 | private float u, v, u2, v2; 41 | private bool regionRotated; 42 | private float regionOriginalWidth, regionOriginalHeight; 43 | private float regionWidth, regionHeight; 44 | private float regionOffsetX, regionOffsetY; 45 | private Material material; 46 | 47 | public SpriteCollectionAttachmentLoader (tk2dSpriteCollectionData sprites) { 48 | if (sprites == null) 49 | throw new ArgumentNullException("sprites cannot be null."); 50 | this.sprites = sprites; 51 | } 52 | 53 | private void ProcessSpriteDefinition (String name) { 54 | // Strip folder names. 55 | int index = name.LastIndexOfAny(new char[] {'/', '\\'}); 56 | if (index != -1) 57 | name = name.Substring(index + 1); 58 | 59 | tk2dSpriteDefinition def = sprites.inst.GetSpriteDefinition(name); 60 | 61 | if (def == null) { 62 | Debug.Log("Sprite not found in atlas: " + name, sprites); 63 | throw new Exception("Sprite not found in atlas: " + name); 64 | } 65 | if (def.complexGeometry) 66 | throw new NotImplementedException("Complex geometry is not supported: " + name); 67 | if (def.flipped == tk2dSpriteDefinition.FlipMode.TPackerCW) 68 | throw new NotImplementedException("Only 2D Toolkit atlases are supported: " + name); 69 | 70 | Vector2 minTexCoords = Vector2.one, maxTexCoords = Vector2.zero; 71 | for (int i = 0; i < def.uvs.Length; ++i) { 72 | Vector2 uv = def.uvs[i]; 73 | minTexCoords = Vector2.Min(minTexCoords, uv); 74 | maxTexCoords = Vector2.Max(maxTexCoords, uv); 75 | } 76 | regionRotated = def.flipped == tk2dSpriteDefinition.FlipMode.Tk2d; 77 | if (regionRotated) { 78 | float temp = minTexCoords.x; 79 | minTexCoords.x = maxTexCoords.x; 80 | maxTexCoords.x = temp; 81 | } 82 | u = minTexCoords.x; 83 | v = maxTexCoords.y; 84 | u2 = maxTexCoords.x; 85 | v2 = minTexCoords.y; 86 | 87 | regionOriginalWidth = (int)(def.untrimmedBoundsData[1].x / def.texelSize.x); 88 | regionOriginalHeight = (int)(def.untrimmedBoundsData[1].y / def.texelSize.y); 89 | 90 | regionWidth = (int)(def.boundsData[1].x / def.texelSize.x); 91 | regionHeight = (int)(def.boundsData[1].y / def.texelSize.y); 92 | 93 | float x0 = def.untrimmedBoundsData[0].x - def.untrimmedBoundsData[1].x / 2; 94 | float x1 = def.boundsData[0].x - def.boundsData[1].x / 2; 95 | regionOffsetX = (int)((x1 - x0) / def.texelSize.x); 96 | 97 | float y0 = def.untrimmedBoundsData[0].y - def.untrimmedBoundsData[1].y / 2; 98 | float y1 = def.boundsData[0].y - def.boundsData[1].y / 2; 99 | regionOffsetY = (int)((y1 - y0) / def.texelSize.y); 100 | 101 | material = def.materialInst; 102 | } 103 | 104 | public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { 105 | ProcessSpriteDefinition(path); 106 | 107 | RegionAttachment region = new RegionAttachment(name); 108 | region.Path = path; 109 | region.RendererObject = material; 110 | region.SetUVs(u, v, u2, v2, regionRotated); 111 | region.RegionOriginalWidth = regionOriginalWidth; 112 | region.RegionOriginalHeight = regionOriginalHeight; 113 | region.RegionWidth = regionWidth; 114 | region.RegionHeight = regionHeight; 115 | region.RegionOffsetX = regionOffsetX; 116 | region.RegionOffsetY = regionOffsetY; 117 | return region; 118 | } 119 | 120 | public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { 121 | ProcessSpriteDefinition(path); 122 | 123 | MeshAttachment mesh = new MeshAttachment(name); 124 | mesh.Path = path; 125 | mesh.RendererObject = material; 126 | mesh.RegionU = u; 127 | mesh.RegionV = v; 128 | mesh.RegionU2 = u2; 129 | mesh.RegionV2 = v2; 130 | mesh.RegionRotate = regionRotated; 131 | mesh.RegionOriginalWidth = regionOriginalWidth; 132 | mesh.RegionOriginalHeight = regionOriginalHeight; 133 | mesh.RegionWidth = regionWidth; 134 | mesh.RegionHeight = regionHeight; 135 | mesh.RegionOffsetX = regionOffsetX; 136 | mesh.RegionOffsetY = regionOffsetY; 137 | return mesh; 138 | } 139 | 140 | public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path) { 141 | ProcessSpriteDefinition(path); 142 | 143 | SkinnedMeshAttachment mesh = new SkinnedMeshAttachment(name); 144 | mesh.Path = path; 145 | mesh.RendererObject = material; 146 | mesh.RegionU = u; 147 | mesh.RegionV = v; 148 | mesh.RegionU2 = u2; 149 | mesh.RegionV2 = v2; 150 | mesh.RegionRotate = regionRotated; 151 | mesh.RegionOriginalWidth = regionOriginalWidth; 152 | mesh.RegionOriginalHeight = regionOriginalHeight; 153 | mesh.RegionWidth = regionWidth; 154 | mesh.RegionHeight = regionHeight; 155 | mesh.RegionOffsetX = regionOffsetX; 156 | mesh.RegionOffsetY = regionOffsetY; 157 | return mesh; 158 | } 159 | 160 | public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { 161 | return new BoundingBoxAttachment(name); 162 | } 163 | } 164 | #endif 165 | --------------------------------------------------------------------------------