diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b4f057b3..6232a830a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -183,6 +183,7 @@ * Moved `Modules/AnimationMatchModifier` directory to `Spine Examples/Scripts/MecanimAnimationMatchModifier`. * Moved `SkeletonRagdoll` and `SkeletonRagdoll2D` components from `Modules/Ragdoll` directory to `Spine Examples/Scripts/Sample Components/SkeletonUtility Modules`. * Moved `AttachmentTools.cs` to `Utility` directory. + * Split the file `AttachmentTools` into 4 new files for each contained class. No namespace or other API changes performed. * Moved `SkeletonExtensions.cs` to `Utility` directory. * Moved `Modules/YieldInstructions` directory to `Utility/YieldInstructions`. * Moved corresponding editor scripts of the above components to restructured directories as well. diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentTools.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs similarity index 57% rename from spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentTools.cs rename to spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs index cb046318e..31f96179e 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentTools.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs @@ -32,179 +32,7 @@ using System.Collections.Generic; using System.Collections; namespace Spine.Unity.AttachmentTools { - public static class AttachmentRegionExtensions { - #region GetRegion - /// - /// Tries to get the region (image) of a renderable attachment. If the attachment is not renderable, it returns null. - public static AtlasRegion GetRegion (this Attachment attachment) { - var renderableAttachment = attachment as IHasRendererObject; - if (renderableAttachment != null) - return renderableAttachment.RendererObject as AtlasRegion; - - return null; - } - - /// Gets the region (image) of a RegionAttachment - public static AtlasRegion GetRegion (this RegionAttachment regionAttachment) { - return regionAttachment.RendererObject as AtlasRegion; - } - - /// Gets the region (image) of a MeshAttachment - public static AtlasRegion GetRegion (this MeshAttachment meshAttachment) { - return meshAttachment.RendererObject as AtlasRegion; - } - #endregion - #region SetRegion - /// - /// Tries to set the region (image) of a renderable attachment. If the attachment is not renderable, nothing is applied. - public static void SetRegion (this Attachment attachment, AtlasRegion region, bool updateOffset = true) { - var regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) - regionAttachment.SetRegion(region, updateOffset); - - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) - meshAttachment.SetRegion(region, updateOffset); - } - - /// Sets the region (image) of a RegionAttachment - public static void SetRegion (this RegionAttachment attachment, AtlasRegion region, bool updateOffset = true) { - if (region == null) throw new System.ArgumentNullException("region"); - - // (AtlasAttachmentLoader.cs) - attachment.RendererObject = region; - attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - - if (updateOffset) attachment.UpdateOffset(); - } - - /// Sets the region (image) of a MeshAttachment - public static void SetRegion (this MeshAttachment attachment, AtlasRegion region, bool updateUVs = true) { - if (region == null) throw new System.ArgumentNullException("region"); - - // (AtlasAttachmentLoader.cs) - attachment.RendererObject = region; - attachment.RegionU = region.u; - attachment.RegionV = region.v; - attachment.RegionU2 = region.u2; - attachment.RegionV2 = region.v2; - attachment.RegionRotate = region.rotate; - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - - if (updateUVs) attachment.UpdateUVs(); - } - #endregion - - #region Runtime RegionAttachments - /// - /// Creates a RegionAttachment based on a sprite. This method creates a real, usable AtlasRegion. That AtlasRegion uses a new AtlasPage with the Material provided./// - public static RegionAttachment ToRegionAttachment (this Sprite sprite, Material material, float rotation = 0f) { - return sprite.ToRegionAttachment(material.ToSpineAtlasPage(), rotation); - } - - /// - /// Creates a RegionAttachment based on a sprite. This method creates a real, usable AtlasRegion. That AtlasRegion uses the AtlasPage provided./// - public static RegionAttachment ToRegionAttachment (this Sprite sprite, AtlasPage page, float rotation = 0f) { - if (sprite == null) throw new System.ArgumentNullException("sprite"); - if (page == null) throw new System.ArgumentNullException("page"); - var region = sprite.ToAtlasRegion(page); - var unitsPerPixel = 1f / sprite.pixelsPerUnit; - return region.ToRegionAttachment(sprite.name, unitsPerPixel, rotation); - } - - /// - /// Creates a Spine.AtlasRegion that uses a premultiplied alpha duplicate texture of the Sprite's texture data. Returns a RegionAttachment that uses it. Use this if you plan to use a premultiply alpha shader such as "Spine/Skeleton" - public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Shader shader, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, Material materialPropertySource = null, float rotation = 0f) { - if (sprite == null) throw new System.ArgumentNullException("sprite"); - if (shader == null) throw new System.ArgumentNullException("shader"); - var region = sprite.ToAtlasRegionPMAClone(shader, textureFormat, mipmaps, materialPropertySource); - var unitsPerPixel = 1f / sprite.pixelsPerUnit; - return region.ToRegionAttachment(sprite.name, unitsPerPixel, rotation); - } - - public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Material materialPropertySource, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, float rotation = 0f) { - return sprite.ToRegionAttachmentPMAClone(materialPropertySource.shader, textureFormat, mipmaps, materialPropertySource, rotation); - } - - /// - /// Creates a new RegionAttachment from a given AtlasRegion. - public static RegionAttachment ToRegionAttachment (this AtlasRegion region, string attachmentName, float scale = 0.01f, float rotation = 0f) { - if (string.IsNullOrEmpty(attachmentName)) throw new System.ArgumentException("attachmentName can't be null or empty.", "attachmentName"); - if (region == null) throw new System.ArgumentNullException("region"); - - // (AtlasAttachmentLoader.cs) - var attachment = new RegionAttachment(attachmentName); - - attachment.RendererObject = region; - attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - - attachment.Path = region.name; - attachment.scaleX = 1; - attachment.scaleY = 1; - attachment.rotation = rotation; - - attachment.r = 1; - attachment.g = 1; - attachment.b = 1; - attachment.a = 1; - - // pass OriginalWidth and OriginalHeight because UpdateOffset uses it in its calculation. - attachment.width = attachment.regionOriginalWidth * scale; - attachment.height = attachment.regionOriginalHeight * scale; - - attachment.SetColor(Color.white); - attachment.UpdateOffset(); - return attachment; - } - - /// Sets the scale. Call regionAttachment.UpdateOffset to apply the change. - public static void SetScale (this RegionAttachment regionAttachment, Vector2 scale) { - regionAttachment.scaleX = scale.x; - regionAttachment.scaleY = scale.y; - } - - /// Sets the scale. Call regionAttachment.UpdateOffset to apply the change. - public static void SetScale (this RegionAttachment regionAttachment, float x, float y) { - regionAttachment.scaleX = x; - regionAttachment.scaleY = y; - } - - /// Sets the position offset. Call regionAttachment.UpdateOffset to apply the change. - public static void SetPositionOffset (this RegionAttachment regionAttachment, Vector2 offset) { - regionAttachment.x = offset.x; - regionAttachment.y = offset.y; - } - - /// Sets the position offset. Call regionAttachment.UpdateOffset to apply the change. - public static void SetPositionOffset (this RegionAttachment regionAttachment, float x, float y) { - regionAttachment.x = x; - regionAttachment.y = y; - } - - /// Sets the rotation. Call regionAttachment.UpdateOffset to apply the change. - public static void SetRotation (this RegionAttachment regionAttachment, float rotation) { - regionAttachment.rotation = rotation; - } - #endregion - } - + public static class AtlasUtilities { internal const TextureFormat SpineTextureFormat = TextureFormat.RGBA32; internal const float DefaultMipmapBias = -0.5f; @@ -753,212 +581,4 @@ namespace Spine.Unity.AttachmentTools { return (value - a) / (b - a); } } - - public static class SkinUtilities { - - #region Skeleton Skin Extensions - /// - /// Convenience method for duplicating a skeleton's current active skin so changes to it will not affect other skeleton instances. . - public static Skin UnshareSkin (this Skeleton skeleton, bool includeDefaultSkin, bool unshareAttachments, AnimationState state = null) { - // 1. Copy the current skin and set the skeleton's skin to the new one. - var newSkin = skeleton.GetClonedSkin("cloned skin", includeDefaultSkin, unshareAttachments, true); - skeleton.SetSkin(newSkin); - - // 2. Apply correct attachments: skeleton.SetToSetupPose + animationState.Apply - if (state != null) { - skeleton.SetToSetupPose(); - state.Apply(skeleton); - } - - // 3. Return unshared skin. - return newSkin; - } - - public static Skin GetClonedSkin (this Skeleton skeleton, string newSkinName, bool includeDefaultSkin = false, bool cloneAttachments = false, bool cloneMeshesAsLinked = true) { - var newSkin = new Skin(newSkinName); // may have null name. Harmless. - var defaultSkin = skeleton.data.DefaultSkin; - var activeSkin = skeleton.skin; - - if (includeDefaultSkin) - defaultSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked); - - if (activeSkin != null) - activeSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked); - - return newSkin; - } - #endregion - - /// - /// Gets a shallow copy of the skin. The cloned skin's attachments are shared with the original skin. - public static Skin GetClone (this Skin original) { - var newSkin = new Skin(original.name + " clone"); - var newSkinAttachments = newSkin.Attachments; - - foreach (DictionaryEntry a in original.Attachments) - newSkinAttachments[a.Key] = a.Value; - - return newSkin; - } - - /// Adds an attachment to the skin for the specified slot index and name. If the name already exists for the slot, the previous value is replaced. - public static void SetAttachment (this Skin skin, string slotName, string keyName, Attachment attachment, Skeleton skeleton) { - int slotIndex = skeleton.FindSlotIndex(slotName); - if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null."); - if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName"); - skin.SetAttachment(slotIndex, keyName, attachment); - } - - /// Adds skin items from another skin. For items that already exist, the previous values are replaced. - public static void AddAttachments (this Skin skin, Skin otherSkin) { - if (otherSkin == null) return; - otherSkin.CopyTo(skin, true, false); - } - - /// Gets an attachment from the skin for the specified slot index and name. - public static Attachment GetAttachment (this Skin skin, string slotName, string keyName, Skeleton skeleton) { - int slotIndex = skeleton.FindSlotIndex(slotName); - if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null."); - if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName"); - return skin.GetAttachment(slotIndex, keyName); - } - - /// Adds an attachment to the skin for the specified slot index and name. If the name already exists for the slot, the previous value is replaced. - public static void SetAttachment (this Skin skin, int slotIndex, string keyName, Attachment attachment) { - skin.SetAttachment(slotIndex, keyName, attachment); - } - - public static void RemoveAttachment (this Skin skin, string slotName, string keyName, SkeletonData skeletonData) { - int slotIndex = skeletonData.FindSlotIndex(slotName); - if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "skeletonData cannot be null."); - if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName"); - skin.RemoveAttachment(slotIndex, keyName); - } - - public static void Clear (this Skin skin) { - skin.Attachments.Clear(); - } - - //[System.Obsolete] - public static void Append (this Skin destination, Skin source) { - source.CopyTo(destination, true, false); - } - - public static void CopyTo (this Skin source, Skin destination, bool overwrite, bool cloneAttachments, bool cloneMeshesAsLinked = true) { - var sourceAttachments = source.Attachments; - var destinationAttachments = destination.Attachments; - - if (cloneAttachments) { - if (overwrite) { - foreach (DictionaryEntry e in sourceAttachments) - destinationAttachments[e.Key] = ((Attachment)e.Value).GetCopy(cloneMeshesAsLinked); - } else { - foreach (DictionaryEntry e in sourceAttachments) { - if (destinationAttachments.Contains(e.Key)) continue; - destinationAttachments.Add(e.Key, ((Attachment)e.Value).GetCopy(cloneMeshesAsLinked)); - } - } - } else { - if (overwrite) { - foreach (DictionaryEntry e in sourceAttachments) - destinationAttachments[e.Key] = e.Value; - } else { - foreach (DictionaryEntry e in sourceAttachments) { - if (destinationAttachments.Contains(e.Key)) continue; - destinationAttachments.Add(e.Key, e.Value); - } - } - } - } - - - } - - public static class AttachmentCloneExtensions { - /// - /// Clones the attachment. - public static Attachment GetCopy (this Attachment o, bool cloneMeshesAsLinked) { - var meshAttachment = o as MeshAttachment; - if (meshAttachment != null && cloneMeshesAsLinked) - return meshAttachment.NewLinkedMesh(); - return o.Copy(); - } - - #region Runtime Linked MeshAttachments - /// - /// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to the AtlasRegion provided. - public static MeshAttachment GetLinkedMesh (this MeshAttachment o, string newLinkedMeshName, AtlasRegion region) { - if (region == null) throw new System.ArgumentNullException("region"); - MeshAttachment mesh = o.NewLinkedMesh(); - mesh.SetRegion(region, false); - return mesh; - } - - /// - /// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to an AtlasRegion generated from a Sprite. The AtlasRegion will be mapped to a new Material based on the shader. - /// For better caching and batching, use GetLinkedMesh(string, AtlasRegion, bool) - public static MeshAttachment GetLinkedMesh (this MeshAttachment o, Sprite sprite, Shader shader, Material materialPropertySource = null) { - var m = new Material(shader); - if (materialPropertySource != null) { - m.CopyPropertiesFromMaterial(materialPropertySource); - m.shaderKeywords = materialPropertySource.shaderKeywords; - } - return o.GetLinkedMesh(sprite.name, sprite.ToAtlasRegion()); - } - - /// - /// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to an AtlasRegion generated from a Sprite. The AtlasRegion will be mapped to a new Material based on the shader. - /// For better caching and batching, use GetLinkedMesh(string, AtlasRegion, bool) - public static MeshAttachment GetLinkedMesh (this MeshAttachment o, Sprite sprite, Material materialPropertySource) { - return o.GetLinkedMesh(sprite, materialPropertySource.shader, materialPropertySource); - } - #endregion - - #region RemappedClone Convenience Methods - /// - /// Gets a clone of the attachment remapped with a sprite image. - /// The remapped clone. - /// The original attachment. - /// The sprite whose texture to use. - /// The source material used to copy the shader and material properties from. - /// If true, a premultiply alpha clone of the original texture will be created. - /// If true MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment. - /// If true the size of the original attachment will be followed, instead of using the Sprite size. - public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial, bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false) { - var atlasRegion = premultiplyAlpha ? sprite.ToAtlasRegionPMAClone(sourceMaterial) : sprite.ToAtlasRegion(new Material(sourceMaterial) { mainTexture = sprite.texture } ); - return o.GetRemappedClone(atlasRegion, cloneMeshAsLinked, useOriginalRegionSize, 1f/sprite.pixelsPerUnit); - } - - /// - /// Gets a clone of the attachment remapped with an atlasRegion image. - /// The remapped clone. - /// The original attachment. - /// Atlas region. - /// If true MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment. - /// If true the size of the original attachment will be followed, instead of using the Sprite size. - /// Unity units per pixel scale used to scale the atlas region size when not using the original region size. - public static Attachment GetRemappedClone (this Attachment o, AtlasRegion atlasRegion, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false, float scale = 0.01f) { - var regionAttachment = o as RegionAttachment; - if (regionAttachment != null) { - RegionAttachment newAttachment = (RegionAttachment)regionAttachment.Copy(); - newAttachment.SetRegion(atlasRegion, false); - if (!useOriginalRegionSize) { - newAttachment.width = atlasRegion.width * scale; - newAttachment.height = atlasRegion.height * scale; - } - newAttachment.UpdateOffset(); - return newAttachment; - } else { - var meshAttachment = o as MeshAttachment; - if (meshAttachment != null) { - MeshAttachment newAttachment = cloneMeshAsLinked ? meshAttachment.NewLinkedMesh() : (MeshAttachment)meshAttachment.Copy(); - newAttachment.SetRegion(atlasRegion); - return newAttachment; - } - } - - return o.GetCopy(true); // Non-renderable Attachments will return as normal cloned attachments. - } - #endregion - } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentTools.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs.meta similarity index 76% rename from spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentTools.cs.meta rename to spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs.meta index 68ad280ef..32d291e25 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentTools.cs.meta +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 8dd46dbf979fcb7459246cd37aad09ef -timeCreated: 1478437807 +guid: 25ceef568a3dad448bf8a14fcc326964 +timeCreated: 1563321428 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs new file mode 100644 index 000000000..16bd1c5a2 --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs @@ -0,0 +1,123 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated May 1, 2019. Replaces all prior versions. + * + * Copyright (c) 2013-2019, Esoteric Software LLC + * + * Integration of the Spine Runtimes into software or otherwise creating + * derivative works of the Spine Runtimes is permitted under the terms and + * conditions of Section 2 of the Spine Editor License Agreement: + * http://esotericsoftware.com/spine-editor-license + * + * Otherwise, it is permitted to integrate the Spine Runtimes into software + * or otherwise create derivative works of the Spine Runtimes (collectively, + * "Products"), provided that each user of the Products must obtain their own + * Spine Editor license and redistribution of the Products in any form must + * include this license and copyright notice. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS + * INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using UnityEngine; +using System.Collections.Generic; +using System.Collections; + +namespace Spine.Unity.AttachmentTools { + + public static class AttachmentCloneExtensions { + /// + /// Clones the attachment. + public static Attachment GetCopy (this Attachment o, bool cloneMeshesAsLinked) { + var meshAttachment = o as MeshAttachment; + if (meshAttachment != null && cloneMeshesAsLinked) + return meshAttachment.NewLinkedMesh(); + return o.Copy(); + } + + #region Runtime Linked MeshAttachments + /// + /// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to the AtlasRegion provided. + public static MeshAttachment GetLinkedMesh (this MeshAttachment o, string newLinkedMeshName, AtlasRegion region) { + if (region == null) throw new System.ArgumentNullException("region"); + MeshAttachment mesh = o.NewLinkedMesh(); + mesh.SetRegion(region, false); + return mesh; + } + + /// + /// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to an AtlasRegion generated from a Sprite. The AtlasRegion will be mapped to a new Material based on the shader. + /// For better caching and batching, use GetLinkedMesh(string, AtlasRegion, bool) + public static MeshAttachment GetLinkedMesh (this MeshAttachment o, Sprite sprite, Shader shader, Material materialPropertySource = null) { + var m = new Material(shader); + if (materialPropertySource != null) { + m.CopyPropertiesFromMaterial(materialPropertySource); + m.shaderKeywords = materialPropertySource.shaderKeywords; + } + return o.GetLinkedMesh(sprite.name, sprite.ToAtlasRegion()); + } + + /// + /// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to an AtlasRegion generated from a Sprite. The AtlasRegion will be mapped to a new Material based on the shader. + /// For better caching and batching, use GetLinkedMesh(string, AtlasRegion, bool) + public static MeshAttachment GetLinkedMesh (this MeshAttachment o, Sprite sprite, Material materialPropertySource) { + return o.GetLinkedMesh(sprite, materialPropertySource.shader, materialPropertySource); + } + #endregion + + #region RemappedClone Convenience Methods + /// + /// Gets a clone of the attachment remapped with a sprite image. + /// The remapped clone. + /// The original attachment. + /// The sprite whose texture to use. + /// The source material used to copy the shader and material properties from. + /// If true, a premultiply alpha clone of the original texture will be created. + /// If true MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment. + /// If true the size of the original attachment will be followed, instead of using the Sprite size. + public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial, bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false) { + var atlasRegion = premultiplyAlpha ? sprite.ToAtlasRegionPMAClone(sourceMaterial) : sprite.ToAtlasRegion(new Material(sourceMaterial) { mainTexture = sprite.texture } ); + return o.GetRemappedClone(atlasRegion, cloneMeshAsLinked, useOriginalRegionSize, 1f/sprite.pixelsPerUnit); + } + + /// + /// Gets a clone of the attachment remapped with an atlasRegion image. + /// The remapped clone. + /// The original attachment. + /// Atlas region. + /// If true MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment. + /// If true the size of the original attachment will be followed, instead of using the Sprite size. + /// Unity units per pixel scale used to scale the atlas region size when not using the original region size. + public static Attachment GetRemappedClone (this Attachment o, AtlasRegion atlasRegion, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false, float scale = 0.01f) { + var regionAttachment = o as RegionAttachment; + if (regionAttachment != null) { + RegionAttachment newAttachment = (RegionAttachment)regionAttachment.Copy(); + newAttachment.SetRegion(atlasRegion, false); + if (!useOriginalRegionSize) { + newAttachment.width = atlasRegion.width * scale; + newAttachment.height = atlasRegion.height * scale; + } + newAttachment.UpdateOffset(); + return newAttachment; + } else { + var meshAttachment = o as MeshAttachment; + if (meshAttachment != null) { + MeshAttachment newAttachment = cloneMeshAsLinked ? meshAttachment.NewLinkedMesh() : (MeshAttachment)meshAttachment.Copy(); + newAttachment.SetRegion(atlasRegion); + return newAttachment; + } + } + + return o.GetCopy(true); // Non-renderable Attachments will return as normal cloned attachments. + } + #endregion + } +} diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs.meta new file mode 100644 index 000000000..4d6580e62 --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3431ed563b2c62f4c8c974a99365ba52 +timeCreated: 1563321428 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs new file mode 100644 index 000000000..32d219655 --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs @@ -0,0 +1,207 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated May 1, 2019. Replaces all prior versions. + * + * Copyright (c) 2013-2019, Esoteric Software LLC + * + * Integration of the Spine Runtimes into software or otherwise creating + * derivative works of the Spine Runtimes is permitted under the terms and + * conditions of Section 2 of the Spine Editor License Agreement: + * http://esotericsoftware.com/spine-editor-license + * + * Otherwise, it is permitted to integrate the Spine Runtimes into software + * or otherwise create derivative works of the Spine Runtimes (collectively, + * "Products"), provided that each user of the Products must obtain their own + * Spine Editor license and redistribution of the Products in any form must + * include this license and copyright notice. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS + * INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using UnityEngine; +using System.Collections.Generic; +using System.Collections; + +namespace Spine.Unity.AttachmentTools { + public static class AttachmentRegionExtensions { + #region GetRegion + /// + /// Tries to get the region (image) of a renderable attachment. If the attachment is not renderable, it returns null. + public static AtlasRegion GetRegion (this Attachment attachment) { + var renderableAttachment = attachment as IHasRendererObject; + if (renderableAttachment != null) + return renderableAttachment.RendererObject as AtlasRegion; + + return null; + } + + /// Gets the region (image) of a RegionAttachment + public static AtlasRegion GetRegion (this RegionAttachment regionAttachment) { + return regionAttachment.RendererObject as AtlasRegion; + } + + /// Gets the region (image) of a MeshAttachment + public static AtlasRegion GetRegion (this MeshAttachment meshAttachment) { + return meshAttachment.RendererObject as AtlasRegion; + } + #endregion + #region SetRegion + /// + /// Tries to set the region (image) of a renderable attachment. If the attachment is not renderable, nothing is applied. + public static void SetRegion (this Attachment attachment, AtlasRegion region, bool updateOffset = true) { + var regionAttachment = attachment as RegionAttachment; + if (regionAttachment != null) + regionAttachment.SetRegion(region, updateOffset); + + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) + meshAttachment.SetRegion(region, updateOffset); + } + + /// Sets the region (image) of a RegionAttachment + public static void SetRegion (this RegionAttachment attachment, AtlasRegion region, bool updateOffset = true) { + if (region == null) throw new System.ArgumentNullException("region"); + + // (AtlasAttachmentLoader.cs) + attachment.RendererObject = region; + attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + + if (updateOffset) attachment.UpdateOffset(); + } + + /// Sets the region (image) of a MeshAttachment + public static void SetRegion (this MeshAttachment attachment, AtlasRegion region, bool updateUVs = true) { + if (region == null) throw new System.ArgumentNullException("region"); + + // (AtlasAttachmentLoader.cs) + attachment.RendererObject = region; + attachment.RegionU = region.u; + attachment.RegionV = region.v; + attachment.RegionU2 = region.u2; + attachment.RegionV2 = region.v2; + attachment.RegionRotate = region.rotate; + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + + if (updateUVs) attachment.UpdateUVs(); + } + #endregion + + #region Runtime RegionAttachments + /// + /// Creates a RegionAttachment based on a sprite. This method creates a real, usable AtlasRegion. That AtlasRegion uses a new AtlasPage with the Material provided./// + public static RegionAttachment ToRegionAttachment (this Sprite sprite, Material material, float rotation = 0f) { + return sprite.ToRegionAttachment(material.ToSpineAtlasPage(), rotation); + } + + /// + /// Creates a RegionAttachment based on a sprite. This method creates a real, usable AtlasRegion. That AtlasRegion uses the AtlasPage provided./// + public static RegionAttachment ToRegionAttachment (this Sprite sprite, AtlasPage page, float rotation = 0f) { + if (sprite == null) throw new System.ArgumentNullException("sprite"); + if (page == null) throw new System.ArgumentNullException("page"); + var region = sprite.ToAtlasRegion(page); + var unitsPerPixel = 1f / sprite.pixelsPerUnit; + return region.ToRegionAttachment(sprite.name, unitsPerPixel, rotation); + } + + /// + /// Creates a Spine.AtlasRegion that uses a premultiplied alpha duplicate texture of the Sprite's texture data. Returns a RegionAttachment that uses it. Use this if you plan to use a premultiply alpha shader such as "Spine/Skeleton" + public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Shader shader, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, Material materialPropertySource = null, float rotation = 0f) { + if (sprite == null) throw new System.ArgumentNullException("sprite"); + if (shader == null) throw new System.ArgumentNullException("shader"); + var region = sprite.ToAtlasRegionPMAClone(shader, textureFormat, mipmaps, materialPropertySource); + var unitsPerPixel = 1f / sprite.pixelsPerUnit; + return region.ToRegionAttachment(sprite.name, unitsPerPixel, rotation); + } + + public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Material materialPropertySource, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, float rotation = 0f) { + return sprite.ToRegionAttachmentPMAClone(materialPropertySource.shader, textureFormat, mipmaps, materialPropertySource, rotation); + } + + /// + /// Creates a new RegionAttachment from a given AtlasRegion. + public static RegionAttachment ToRegionAttachment (this AtlasRegion region, string attachmentName, float scale = 0.01f, float rotation = 0f) { + if (string.IsNullOrEmpty(attachmentName)) throw new System.ArgumentException("attachmentName can't be null or empty.", "attachmentName"); + if (region == null) throw new System.ArgumentNullException("region"); + + // (AtlasAttachmentLoader.cs) + var attachment = new RegionAttachment(attachmentName); + + attachment.RendererObject = region; + attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + + attachment.Path = region.name; + attachment.scaleX = 1; + attachment.scaleY = 1; + attachment.rotation = rotation; + + attachment.r = 1; + attachment.g = 1; + attachment.b = 1; + attachment.a = 1; + + // pass OriginalWidth and OriginalHeight because UpdateOffset uses it in its calculation. + attachment.width = attachment.regionOriginalWidth * scale; + attachment.height = attachment.regionOriginalHeight * scale; + + attachment.SetColor(Color.white); + attachment.UpdateOffset(); + return attachment; + } + + /// Sets the scale. Call regionAttachment.UpdateOffset to apply the change. + public static void SetScale (this RegionAttachment regionAttachment, Vector2 scale) { + regionAttachment.scaleX = scale.x; + regionAttachment.scaleY = scale.y; + } + + /// Sets the scale. Call regionAttachment.UpdateOffset to apply the change. + public static void SetScale (this RegionAttachment regionAttachment, float x, float y) { + regionAttachment.scaleX = x; + regionAttachment.scaleY = y; + } + + /// Sets the position offset. Call regionAttachment.UpdateOffset to apply the change. + public static void SetPositionOffset (this RegionAttachment regionAttachment, Vector2 offset) { + regionAttachment.x = offset.x; + regionAttachment.y = offset.y; + } + + /// Sets the position offset. Call regionAttachment.UpdateOffset to apply the change. + public static void SetPositionOffset (this RegionAttachment regionAttachment, float x, float y) { + regionAttachment.x = x; + regionAttachment.y = y; + } + + /// Sets the rotation. Call regionAttachment.UpdateOffset to apply the change. + public static void SetRotation (this RegionAttachment regionAttachment, float rotation) { + regionAttachment.rotation = rotation; + } + #endregion + } +} diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs.meta new file mode 100644 index 000000000..58262113b --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7e7eac783deea004e9bc403eca68a7dc +timeCreated: 1563321428 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkinUtilities.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkinUtilities.cs new file mode 100644 index 000000000..c8b4ce92d --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkinUtilities.cs @@ -0,0 +1,156 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated May 1, 2019. Replaces all prior versions. + * + * Copyright (c) 2013-2019, Esoteric Software LLC + * + * Integration of the Spine Runtimes into software or otherwise creating + * derivative works of the Spine Runtimes is permitted under the terms and + * conditions of Section 2 of the Spine Editor License Agreement: + * http://esotericsoftware.com/spine-editor-license + * + * Otherwise, it is permitted to integrate the Spine Runtimes into software + * or otherwise create derivative works of the Spine Runtimes (collectively, + * "Products"), provided that each user of the Products must obtain their own + * Spine Editor license and redistribution of the Products in any form must + * include this license and copyright notice. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS + * INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using UnityEngine; +using System.Collections.Generic; +using System.Collections; + +namespace Spine.Unity.AttachmentTools { + + public static class SkinUtilities { + + #region Skeleton Skin Extensions + /// + /// Convenience method for duplicating a skeleton's current active skin so changes to it will not affect other skeleton instances. . + public static Skin UnshareSkin (this Skeleton skeleton, bool includeDefaultSkin, bool unshareAttachments, AnimationState state = null) { + // 1. Copy the current skin and set the skeleton's skin to the new one. + var newSkin = skeleton.GetClonedSkin("cloned skin", includeDefaultSkin, unshareAttachments, true); + skeleton.SetSkin(newSkin); + + // 2. Apply correct attachments: skeleton.SetToSetupPose + animationState.Apply + if (state != null) { + skeleton.SetToSetupPose(); + state.Apply(skeleton); + } + + // 3. Return unshared skin. + return newSkin; + } + + public static Skin GetClonedSkin (this Skeleton skeleton, string newSkinName, bool includeDefaultSkin = false, bool cloneAttachments = false, bool cloneMeshesAsLinked = true) { + var newSkin = new Skin(newSkinName); // may have null name. Harmless. + var defaultSkin = skeleton.data.DefaultSkin; + var activeSkin = skeleton.skin; + + if (includeDefaultSkin) + defaultSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked); + + if (activeSkin != null) + activeSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked); + + return newSkin; + } + #endregion + + /// + /// Gets a shallow copy of the skin. The cloned skin's attachments are shared with the original skin. + public static Skin GetClone (this Skin original) { + var newSkin = new Skin(original.name + " clone"); + var newSkinAttachments = newSkin.Attachments; + + foreach (DictionaryEntry a in original.Attachments) + newSkinAttachments[a.Key] = a.Value; + + return newSkin; + } + + /// Adds an attachment to the skin for the specified slot index and name. If the name already exists for the slot, the previous value is replaced. + public static void SetAttachment (this Skin skin, string slotName, string keyName, Attachment attachment, Skeleton skeleton) { + int slotIndex = skeleton.FindSlotIndex(slotName); + if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null."); + if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName"); + skin.SetAttachment(slotIndex, keyName, attachment); + } + + /// Adds skin items from another skin. For items that already exist, the previous values are replaced. + public static void AddAttachments (this Skin skin, Skin otherSkin) { + if (otherSkin == null) return; + otherSkin.CopyTo(skin, true, false); + } + + /// Gets an attachment from the skin for the specified slot index and name. + public static Attachment GetAttachment (this Skin skin, string slotName, string keyName, Skeleton skeleton) { + int slotIndex = skeleton.FindSlotIndex(slotName); + if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null."); + if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName"); + return skin.GetAttachment(slotIndex, keyName); + } + + /// Adds an attachment to the skin for the specified slot index and name. If the name already exists for the slot, the previous value is replaced. + public static void SetAttachment (this Skin skin, int slotIndex, string keyName, Attachment attachment) { + skin.SetAttachment(slotIndex, keyName, attachment); + } + + public static void RemoveAttachment (this Skin skin, string slotName, string keyName, SkeletonData skeletonData) { + int slotIndex = skeletonData.FindSlotIndex(slotName); + if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "skeletonData cannot be null."); + if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName"); + skin.RemoveAttachment(slotIndex, keyName); + } + + public static void Clear (this Skin skin) { + skin.Attachments.Clear(); + } + + //[System.Obsolete] + public static void Append (this Skin destination, Skin source) { + source.CopyTo(destination, true, false); + } + + public static void CopyTo (this Skin source, Skin destination, bool overwrite, bool cloneAttachments, bool cloneMeshesAsLinked = true) { + var sourceAttachments = source.Attachments; + var destinationAttachments = destination.Attachments; + + if (cloneAttachments) { + if (overwrite) { + foreach (DictionaryEntry e in sourceAttachments) + destinationAttachments[e.Key] = ((Attachment)e.Value).GetCopy(cloneMeshesAsLinked); + } else { + foreach (DictionaryEntry e in sourceAttachments) { + if (destinationAttachments.Contains(e.Key)) continue; + destinationAttachments.Add(e.Key, ((Attachment)e.Value).GetCopy(cloneMeshesAsLinked)); + } + } + } else { + if (overwrite) { + foreach (DictionaryEntry e in sourceAttachments) + destinationAttachments[e.Key] = e.Value; + } else { + foreach (DictionaryEntry e in sourceAttachments) { + if (destinationAttachments.Contains(e.Key)) continue; + destinationAttachments.Add(e.Key, e.Value); + } + } + } + } + + + } + +} diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkinUtilities.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkinUtilities.cs.meta new file mode 100644 index 000000000..5ac1f297b --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkinUtilities.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f4692b9527684d048862210ba3f9834e +timeCreated: 1563321428 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: