diff --git a/CHANGELOG.md b/CHANGELOG.md index c63f22cc6..1182315d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -375,6 +375,7 @@ * Now providing `BeforeApply` update callbacks at all skeleton animation components (`SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic`). * Added `BoundingBoxFollowerGraphic` component. This class is a counterpart of `BoundingBoxFollower` that can be used with `SkeletonGraphic`. * Added Inspector context menu functions `SkeletonRenderer - Add all BoundingBoxFollower GameObjects` and `SkeletonGraphic - Add all BoundingBoxFollowerGraphic GameObjects` that automatically generate bounding box follower GameObjects for every `BoundingBoxAttachment` for all skins of a skeleton. + * `GetRemappedClone()` now provides an additional parameter `pivotShiftsMeshUVCoords` for `MeshAttachment` to prevent uv shifts at a non-central Sprite pivot. This parameter defaults to `true` to maintain previous behaviour. * **Changes of default values** * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`. diff --git a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs index 3d6286301..580d8aa61 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs @@ -94,13 +94,13 @@ namespace Spine.Unity.Examples { // Let's do this for the visor. int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster. Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1 - Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3 + Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords : false); // STEP 1.2 - 1.3 customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4 // And now for the gun. int gunSlotIndex = skeleton.FindSlotIndex(gunSlot); Attachment templateGun = templateSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1 - Attachment newGun = templateGun.GetRemappedClone(gunSprite, sourceMaterial); // STEP 1.2 - 1.3 + Attachment newGun = templateGun.GetRemappedClone(gunSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3 if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4 // customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item. diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs index 82aae46da..f841a02ef 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs @@ -115,6 +115,8 @@ namespace Spine.Unity { nameTable.Clear(); var skeleton = skeletonRenderer.skeleton; + if (skeleton == null) + return; slot = skeleton.FindSlot(slotName); int slotIndex = skeleton.FindSlotIndex(slotName); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs index 106a9810d..674a0fb04 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs @@ -115,6 +115,8 @@ namespace Spine.Unity { nameTable.Clear(); var skeleton = skeletonGraphic.Skeleton; + if (skeleton == null) + return; slot = skeleton.FindSlot(slotName); int slotIndex = skeleton.FindSlotIndex(slotName); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs index f122df3ba..8657ea69d 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs @@ -45,8 +45,18 @@ namespace Spine.Unity.AttachmentTools { /// 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) { + /// If true and the original Attachment is a MeshAttachment, then + /// a non-central sprite pivot will shift uv coords in the opposite direction. Vertices will not be offset in + /// any case when the original Attachment is a MeshAttachment. + public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial, + bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false, + bool pivotShiftsMeshUVCoords = true) { var atlasRegion = premultiplyAlpha ? sprite.ToAtlasRegionPMAClone(sourceMaterial) : sprite.ToAtlasRegion(new Material(sourceMaterial) { mainTexture = sprite.texture } ); + if (!pivotShiftsMeshUVCoords && o is MeshAttachment) { + // prevent non-central sprite pivot setting offsetX/Y and shifting uv coords out of mesh bounds + atlasRegion.offsetX = 0; + atlasRegion.offsetY = 0; + } return o.GetRemappedClone(atlasRegion, cloneMeshAsLinked, useOriginalRegionSize, 1f/sprite.pixelsPerUnit); } diff --git a/spine-xna/src/MeshBatcher.cs b/spine-xna/src/MeshBatcher.cs index 5a81d2575..bcca36aeb 100644 --- a/spine-xna/src/MeshBatcher.cs +++ b/spine-xna/src/MeshBatcher.cs @@ -1,195 +1,195 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated January 1, 2020. Replaces all prior versions. - * - * Copyright (c) 2013-2020, 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. - * - * THE SPINE RUNTIMES ARE 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 - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -using System; -using System.Collections.Generic; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework; - -namespace Spine { - public struct VertexPositionColorTextureColor : IVertexType { - public Vector3 Position; - public Color Color; - public Vector2 TextureCoordinate; - public Color Color2; - - public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration - ( - new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0), - new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0), - new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0), - new VertexElement(24, VertexElementFormat.Color, VertexElementUsage.Color, 1) - ); - - VertexDeclaration IVertexType.VertexDeclaration { - get { return VertexDeclaration; } - } - } - - // #region License - // /* - // Microsoft Public License (Ms-PL) - // MonoGame - Copyright � 2009 The MonoGame Team - // - // All rights reserved. - // - // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not - // accept the license, do not use the software. - // - // 1. Definitions - // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under - // U.S. copyright law. - // - // A "contribution" is the original software, or any additions or changes to the software. - // A "contributor" is any person that distributes its contribution under this license. - // "Licensed patents" are a contributor's patent claims that read directly on its contribution. - // - // 2. Grant of Rights - // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, - // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. - // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, - // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. - // - // 3. Conditions and Limitations - // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. - // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, - // your patent license from such contributor to the software ends automatically. - // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution - // notices that are present in the software. - // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including - // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object - // code form, you may only do so under a license that complies with this license. - // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees - // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent - // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular - // purpose and non-infringement. - // */ - // #endregion License - // - - /// Draws batched meshes. - public class MeshBatcher { - private readonly List items; - private readonly Queue freeItems; - private VertexPositionColorTextureColor[] vertexArray = { }; - private short[] triangles = { }; - - public MeshBatcher () { - items = new List(256); - freeItems = new Queue(256); - EnsureCapacity(256, 512); - } - - /// Returns a pooled MeshItem. - public MeshItem NextItem (int vertexCount, int triangleCount) { - MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem(); - if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTextureColor[vertexCount]; - if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount]; - item.vertexCount = vertexCount; - item.triangleCount = triangleCount; - items.Add(item); - return item; - } - - private void EnsureCapacity (int vertexCount, int triangleCount) { - if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTextureColor[vertexCount]; - if (triangles.Length < triangleCount) triangles = new short[triangleCount]; - } - - public void Draw (GraphicsDevice device) { - if (items.Count == 0) return; - - int itemCount = items.Count; - int vertexCount = 0, triangleCount = 0; - for (int i = 0; i < itemCount; i++) { - MeshItem item = items[i]; - vertexCount += item.vertexCount; - triangleCount += item.triangleCount; - } - EnsureCapacity(vertexCount, triangleCount); - - vertexCount = 0; - triangleCount = 0; - Texture2D lastTexture = null; - for (int i = 0; i < itemCount; i++) { - MeshItem item = items[i]; - int itemVertexCount = item.vertexCount; - - if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) { - FlushVertexArray(device, vertexCount, triangleCount); - vertexCount = 0; - triangleCount = 0; - lastTexture = item.texture; - device.Textures[0] = lastTexture; - if (item.textureLayers != null) { - for (int layer = 1; layer < item.textureLayers.Length; ++layer) - device.Textures[layer] = item.textureLayers[layer]; - } - } - - int[] itemTriangles = item.triangles; - int itemTriangleCount = item.triangleCount; - for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++) - triangles[t] = (short)(itemTriangles[ii] + vertexCount); - triangleCount += itemTriangleCount; - - Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount); - vertexCount += itemVertexCount; - } - FlushVertexArray(device, vertexCount, triangleCount); - } - - public void AfterLastDrawPass () { - int itemCount = items.Count; - for (int i = 0; i < itemCount; i++) { - var item = items[i]; - item.texture = null; - freeItems.Enqueue(item); - } - items.Clear(); - } - - private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) { - if (vertexCount == 0) return; - device.DrawUserIndexedPrimitives( - PrimitiveType.TriangleList, - vertexArray, 0, vertexCount, - triangles, 0, triangleCount / 3, - VertexPositionColorTextureColor.VertexDeclaration); - } - } - - public class MeshItem { - public Texture2D texture = null; - public Texture2D[] textureLayers = null; - public int vertexCount, triangleCount; - public VertexPositionColorTextureColor[] vertices = { }; - public int[] triangles = { }; - } -} +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated January 1, 2020. Replaces all prior versions. + * + * Copyright (c) 2013-2020, 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. + * + * THE SPINE RUNTIMES ARE 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 + * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; + +namespace Spine { + public struct VertexPositionColorTextureColor : IVertexType { + public Vector3 Position; + public Color Color; + public Vector2 TextureCoordinate; + public Color Color2; + + public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration + ( + new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0), + new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0), + new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0), + new VertexElement(24, VertexElementFormat.Color, VertexElementUsage.Color, 1) + ); + + VertexDeclaration IVertexType.VertexDeclaration { + get { return VertexDeclaration; } + } + } + + // #region License + // /* + // Microsoft Public License (Ms-PL) + // MonoGame - Copyright � 2009 The MonoGame Team + // + // All rights reserved. + // + // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not + // accept the license, do not use the software. + // + // 1. Definitions + // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under + // U.S. copyright law. + // + // A "contribution" is the original software, or any additions or changes to the software. + // A "contributor" is any person that distributes its contribution under this license. + // "Licensed patents" are a contributor's patent claims that read directly on its contribution. + // + // 2. Grant of Rights + // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, + // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, + // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + // + // 3. Conditions and Limitations + // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, + // your patent license from such contributor to the software ends automatically. + // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution + // notices that are present in the software. + // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including + // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object + // code form, you may only do so under a license that complies with this license. + // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees + // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent + // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular + // purpose and non-infringement. + // */ + // #endregion License + // + + /// Draws batched meshes. + public class MeshBatcher { + private readonly List items; + private readonly Queue freeItems; + private VertexPositionColorTextureColor[] vertexArray = { }; + private short[] triangles = { }; + + public MeshBatcher () { + items = new List(256); + freeItems = new Queue(256); + EnsureCapacity(256, 512); + } + + /// Returns a pooled MeshItem. + public MeshItem NextItem (int vertexCount, int triangleCount) { + MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem(); + if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTextureColor[vertexCount]; + if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount]; + item.vertexCount = vertexCount; + item.triangleCount = triangleCount; + items.Add(item); + return item; + } + + private void EnsureCapacity (int vertexCount, int triangleCount) { + if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTextureColor[vertexCount]; + if (triangles.Length < triangleCount) triangles = new short[triangleCount]; + } + + public void Draw (GraphicsDevice device) { + if (items.Count == 0) return; + + int itemCount = items.Count; + int vertexCount = 0, triangleCount = 0; + for (int i = 0; i < itemCount; i++) { + MeshItem item = items[i]; + vertexCount += item.vertexCount; + triangleCount += item.triangleCount; + } + EnsureCapacity(vertexCount, triangleCount); + + vertexCount = 0; + triangleCount = 0; + Texture2D lastTexture = null; + for (int i = 0; i < itemCount; i++) { + MeshItem item = items[i]; + int itemVertexCount = item.vertexCount; + + if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) { + FlushVertexArray(device, vertexCount, triangleCount); + vertexCount = 0; + triangleCount = 0; + lastTexture = item.texture; + device.Textures[0] = lastTexture; + if (item.textureLayers != null) { + for (int layer = 1; layer < item.textureLayers.Length; ++layer) + device.Textures[layer] = item.textureLayers[layer]; + } + } + + int[] itemTriangles = item.triangles; + int itemTriangleCount = item.triangleCount; + for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++) + triangles[t] = (short)(itemTriangles[ii] + vertexCount); + triangleCount += itemTriangleCount; + + Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount); + vertexCount += itemVertexCount; + } + FlushVertexArray(device, vertexCount, triangleCount); + } + + public void AfterLastDrawPass () { + int itemCount = items.Count; + for (int i = 0; i < itemCount; i++) { + var item = items[i]; + item.texture = null; + freeItems.Enqueue(item); + } + items.Clear(); + } + + private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) { + if (vertexCount == 0) return; + device.DrawUserIndexedPrimitives( + PrimitiveType.TriangleList, + vertexArray, 0, vertexCount, + triangles, 0, triangleCount / 3, + VertexPositionColorTextureColor.VertexDeclaration); + } + } + + public class MeshItem { + public Texture2D texture = null; + public Texture2D[] textureLayers = null; + public int vertexCount, triangleCount; + public VertexPositionColorTextureColor[] vertices = { }; + public int[] triangles = { }; + } +} diff --git a/spine-xna/src/Util.cs b/spine-xna/src/Util.cs index 54d495ac5..5c6479ad8 100644 --- a/spine-xna/src/Util.cs +++ b/spine-xna/src/Util.cs @@ -1,79 +1,79 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated January 1, 2020. Replaces all prior versions. - * - * Copyright (c) 2013-2020, 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. - * - * THE SPINE RUNTIMES ARE 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 - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -using System; -using System.IO; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -#if WINDOWS_STOREAPP -using System.Threading.Tasks; -using Windows.Storage; -#endif - -namespace Spine { - - static public class Util { -#if WINDOWS_STOREAPP - private static async Task LoadFile(GraphicsDevice device, String path) { - var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; - var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); - try { - return Util.LoadTexture(device, await file.OpenStreamForReadAsync().ConfigureAwait(false)); - } catch (Exception ex) { - throw new Exception("Error reading texture file: " + path, ex); - } - } - - static public Texture2D LoadTexture (GraphicsDevice device, String path) { - return LoadFile(device, path).Result; - } -#else - static public Texture2D LoadTexture (GraphicsDevice device, String path) { - -#if WINDOWS_PHONE - Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); - using (Stream input = stream) { -#else - using (Stream input = new FileStream(path, FileMode.Open, FileAccess.Read)) { -#endif - try { - return Util.LoadTexture(device, input); - } catch (Exception ex) { - throw new Exception("Error reading texture file: " + path, ex); - } - } - } -#endif - - static public Texture2D LoadTexture (GraphicsDevice device, Stream input) { - return Texture2D.FromStream(device, input); - } - } -} +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated January 1, 2020. Replaces all prior versions. + * + * Copyright (c) 2013-2020, 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. + * + * THE SPINE RUNTIMES ARE 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 + * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.IO; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +#if WINDOWS_STOREAPP +using System.Threading.Tasks; +using Windows.Storage; +#endif + +namespace Spine { + + static public class Util { +#if WINDOWS_STOREAPP + private static async Task LoadFile(GraphicsDevice device, String path) { + var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; + var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); + try { + return Util.LoadTexture(device, await file.OpenStreamForReadAsync().ConfigureAwait(false)); + } catch (Exception ex) { + throw new Exception("Error reading texture file: " + path, ex); + } + } + + static public Texture2D LoadTexture (GraphicsDevice device, String path) { + return LoadFile(device, path).Result; + } +#else + static public Texture2D LoadTexture (GraphicsDevice device, String path) { + +#if WINDOWS_PHONE + Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); + using (Stream input = stream) { +#else + using (Stream input = new FileStream(path, FileMode.Open, FileAccess.Read)) { +#endif + try { + return Util.LoadTexture(device, input); + } catch (Exception ex) { + throw new Exception("Error reading texture file: " + path, ex); + } + } + } +#endif + + static public Texture2D LoadTexture (GraphicsDevice device, Stream input) { + return Texture2D.FromStream(device, input); + } + } +} diff --git a/spine-xna/src/XnaTextureLoader.cs b/spine-xna/src/XnaTextureLoader.cs index f31921cba..3aa77e5c1 100644 --- a/spine-xna/src/XnaTextureLoader.cs +++ b/spine-xna/src/XnaTextureLoader.cs @@ -1,94 +1,94 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated January 1, 2020. Replaces all prior versions. - * - * Copyright (c) 2013-2020, 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. - * - * THE SPINE RUNTIMES ARE 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 - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -using System; -using System.IO; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Spine { - public class XnaTextureLoader : TextureLoader { - GraphicsDevice device; - string[] textureLayerSuffixes = null; - - /// - /// Constructor. - /// - /// The graphics device to be used. - /// If true multiple textures layers - /// (e.g. a diffuse/albedo texture and a normal map) are loaded instead of a single texture. - /// Names are constructed based on suffixes added according to the textureSuffixes parameter. - /// If loadMultipleTextureLayers is true, the strings of this array - /// define the path name suffix of each layer to be loaded. Array size must be equal to the number of layers to be loaded. - /// The first array entry is the suffix to be replaced (e.g. "_albedo", or "" for a first layer without a suffix), - /// subsequent array entries contain the suffix to replace the first entry with (e.g. "_normals"). - /// - /// An example would be: - /// new string[] { "", "_normals" } for loading a base diffuse texture named "skeletonname.png" and - /// a normalmap named "skeletonname_normals.png". - public XnaTextureLoader (GraphicsDevice device, bool loadMultipleTextureLayers = false, string[] textureSuffixes = null) { - this.device = device; - if (loadMultipleTextureLayers) - this.textureLayerSuffixes = textureSuffixes; - } - - public void Load (AtlasPage page, String path) { - Texture2D texture = Util.LoadTexture(device, path); - page.width = texture.Width; - page.height = texture.Height; - - if (textureLayerSuffixes == null) { - page.rendererObject = texture; - } - else { - Texture2D[] textureLayersArray = new Texture2D[textureLayerSuffixes.Length]; - textureLayersArray[0] = texture; - for (int layer = 1; layer < textureLayersArray.Length; ++layer) { - string layerPath = GetLayerName(path, textureLayerSuffixes[0], textureLayerSuffixes[layer]); - textureLayersArray[layer] = Util.LoadTexture(device, layerPath); - } - page.rendererObject = textureLayersArray; - } - } - - public void Unload (Object texture) { - ((Texture2D)texture).Dispose(); - } - - private string GetLayerName (string firstLayerPath, string firstLayerSuffix, string replacementSuffix) { - - int suffixLocation = firstLayerPath.LastIndexOf(firstLayerSuffix + "."); - if (suffixLocation == -1) { - throw new Exception(string.Concat("Error composing texture layer name: first texture layer name '", firstLayerPath, - "' does not contain suffix to be replaced: '", firstLayerSuffix, "'")); - } - return firstLayerPath.Remove(suffixLocation, firstLayerSuffix.Length).Insert(suffixLocation, replacementSuffix); - } - } -} +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated January 1, 2020. Replaces all prior versions. + * + * Copyright (c) 2013-2020, 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. + * + * THE SPINE RUNTIMES ARE 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 + * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.IO; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Spine { + public class XnaTextureLoader : TextureLoader { + GraphicsDevice device; + string[] textureLayerSuffixes = null; + + /// + /// Constructor. + /// + /// The graphics device to be used. + /// If true multiple textures layers + /// (e.g. a diffuse/albedo texture and a normal map) are loaded instead of a single texture. + /// Names are constructed based on suffixes added according to the textureSuffixes parameter. + /// If loadMultipleTextureLayers is true, the strings of this array + /// define the path name suffix of each layer to be loaded. Array size must be equal to the number of layers to be loaded. + /// The first array entry is the suffix to be replaced (e.g. "_albedo", or "" for a first layer without a suffix), + /// subsequent array entries contain the suffix to replace the first entry with (e.g. "_normals"). + /// + /// An example would be: + /// new string[] { "", "_normals" } for loading a base diffuse texture named "skeletonname.png" and + /// a normalmap named "skeletonname_normals.png". + public XnaTextureLoader (GraphicsDevice device, bool loadMultipleTextureLayers = false, string[] textureSuffixes = null) { + this.device = device; + if (loadMultipleTextureLayers) + this.textureLayerSuffixes = textureSuffixes; + } + + public void Load (AtlasPage page, String path) { + Texture2D texture = Util.LoadTexture(device, path); + page.width = texture.Width; + page.height = texture.Height; + + if (textureLayerSuffixes == null) { + page.rendererObject = texture; + } + else { + Texture2D[] textureLayersArray = new Texture2D[textureLayerSuffixes.Length]; + textureLayersArray[0] = texture; + for (int layer = 1; layer < textureLayersArray.Length; ++layer) { + string layerPath = GetLayerName(path, textureLayerSuffixes[0], textureLayerSuffixes[layer]); + textureLayersArray[layer] = Util.LoadTexture(device, layerPath); + } + page.rendererObject = textureLayersArray; + } + } + + public void Unload (Object texture) { + ((Texture2D)texture).Dispose(); + } + + private string GetLayerName (string firstLayerPath, string firstLayerSuffix, string replacementSuffix) { + + int suffixLocation = firstLayerPath.LastIndexOf(firstLayerSuffix + "."); + if (suffixLocation == -1) { + throw new Exception(string.Concat("Error composing texture layer name: first texture layer name '", firstLayerPath, + "' does not contain suffix to be replaced: '", firstLayerSuffix, "'")); + } + return firstLayerPath.Remove(suffixLocation, firstLayerSuffix.Length).Insert(suffixLocation, replacementSuffix); + } + } +}